mainfile_with copy
Browse files
app.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
import os
|
| 2 |
import sys
|
|
|
|
| 3 |
|
| 4 |
# ============================================================================
|
| 5 |
# CRITICAL: Set API key BEFORE importing Together
|
|
@@ -16,16 +17,25 @@ os.environ["TOGETHER_API_KEY"] = API_KEY
|
|
| 16 |
|
| 17 |
# NOW import Together and other dependencies
|
| 18 |
import streamlit as st
|
|
|
|
| 19 |
from together import Together
|
| 20 |
from langchain_community.vectorstores import Chroma
|
| 21 |
from langchain_huggingface import HuggingFaceEmbeddings
|
|
|
|
| 22 |
|
| 23 |
# ============================================================================
|
| 24 |
# CONFIGURATION
|
| 25 |
# ============================================================================
|
| 26 |
|
|
|
|
|
|
|
|
|
|
| 27 |
# Vector store configurations
|
| 28 |
VECTOR_STORES = {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
"Paediatrics": {
|
| 30 |
"collection_name": "paedia",
|
| 31 |
"persist_directory": "nelsonpaedia"
|
|
@@ -75,7 +85,7 @@ VECTOR_STORES = {
|
|
| 75 |
# Model configurations
|
| 76 |
EMBED_MODEL = "BAAI/bge-base-en"
|
| 77 |
LLM_MODEL = "Qwen/Qwen3-Next-80B-A3B-Instruct"
|
| 78 |
-
RETRIEVAL_K =
|
| 79 |
|
| 80 |
# ============================================================================
|
| 81 |
# PAGE CONFIG
|
|
@@ -98,6 +108,27 @@ except Exception as e:
|
|
| 98 |
st.error(f"β Failed to initialize Together client: {e}")
|
| 99 |
st.stop()
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
# Initialize embeddings
|
| 102 |
@st.cache_resource
|
| 103 |
def get_embeddings():
|
|
@@ -230,11 +261,46 @@ for i, message in enumerate(st.session_state.chat_history):
|
|
| 230 |
with st.chat_message(message["role"]):
|
| 231 |
st.markdown(message["content"])
|
| 232 |
|
| 233 |
-
# Add copy button for assistant messages
|
| 234 |
if message["role"] == "assistant":
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
|
| 239 |
# Chat input
|
| 240 |
user_input = st.chat_input("Ask me anything about medical topics...")
|
|
@@ -280,9 +346,45 @@ if user_input:
|
|
| 280 |
|
| 281 |
response_placeholder.markdown(full_response)
|
| 282 |
|
| 283 |
-
# Add copy
|
| 284 |
-
|
| 285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
|
| 287 |
# Save assistant response
|
| 288 |
st.session_state.chat_history.append({
|
|
|
|
| 1 |
import os
|
| 2 |
import sys
|
| 3 |
+
import html
|
| 4 |
|
| 5 |
# ============================================================================
|
| 6 |
# CRITICAL: Set API key BEFORE importing Together
|
|
|
|
| 17 |
|
| 18 |
# NOW import Together and other dependencies
|
| 19 |
import streamlit as st
|
| 20 |
+
import streamlit.components.v1
|
| 21 |
from together import Together
|
| 22 |
from langchain_community.vectorstores import Chroma
|
| 23 |
from langchain_huggingface import HuggingFaceEmbeddings
|
| 24 |
+
from huggingface_hub import snapshot_download
|
| 25 |
|
| 26 |
# ============================================================================
|
| 27 |
# CONFIGURATION
|
| 28 |
# ============================================================================
|
| 29 |
|
| 30 |
+
# Your HuggingFace dataset repository containing all vector stores
|
| 31 |
+
DATASET_REPO = "Sbnos/vstoryies"
|
| 32 |
+
|
| 33 |
# Vector store configurations
|
| 34 |
VECTOR_STORES = {
|
| 35 |
+
"General Medicine": {
|
| 36 |
+
"collection_name": "oxfordmed",
|
| 37 |
+
"persist_directory": "oxfordmedbookdir"
|
| 38 |
+
},
|
| 39 |
"Paediatrics": {
|
| 40 |
"collection_name": "paedia",
|
| 41 |
"persist_directory": "nelsonpaedia"
|
|
|
|
| 85 |
# Model configurations
|
| 86 |
EMBED_MODEL = "BAAI/bge-base-en"
|
| 87 |
LLM_MODEL = "Qwen/Qwen3-Next-80B-A3B-Instruct"
|
| 88 |
+
RETRIEVAL_K = 26
|
| 89 |
|
| 90 |
# ============================================================================
|
| 91 |
# PAGE CONFIG
|
|
|
|
| 108 |
st.error(f"β Failed to initialize Together client: {e}")
|
| 109 |
st.stop()
|
| 110 |
|
| 111 |
+
# Download all vector stores from HuggingFace dataset on first run
|
| 112 |
+
@st.cache_resource
|
| 113 |
+
def download_all_vectorstores():
|
| 114 |
+
"""Download all vector stores from HuggingFace dataset repository"""
|
| 115 |
+
if not any(os.path.exists(config["persist_directory"]) for config in VECTOR_STORES.values()):
|
| 116 |
+
with st.spinner("π₯ Downloading vector stores from HuggingFace (one-time setup)..."):
|
| 117 |
+
try:
|
| 118 |
+
snapshot_download(
|
| 119 |
+
repo_id=DATASET_REPO,
|
| 120 |
+
repo_type="dataset",
|
| 121 |
+
local_dir=".",
|
| 122 |
+
allow_patterns=["*"]
|
| 123 |
+
)
|
| 124 |
+
st.success("β
Vector stores downloaded successfully!")
|
| 125 |
+
except Exception as e:
|
| 126 |
+
st.error(f"β Failed to download vector stores: {e}")
|
| 127 |
+
st.stop()
|
| 128 |
+
|
| 129 |
+
# Download vector stores if needed
|
| 130 |
+
download_all_vectorstores()
|
| 131 |
+
|
| 132 |
# Initialize embeddings
|
| 133 |
@st.cache_resource
|
| 134 |
def get_embeddings():
|
|
|
|
| 261 |
with st.chat_message(message["role"]):
|
| 262 |
st.markdown(message["content"])
|
| 263 |
|
| 264 |
+
# Add one-click copy button for assistant messages
|
| 265 |
if message["role"] == "assistant":
|
| 266 |
+
escaped_content = html.escape(message["content"])
|
| 267 |
+
|
| 268 |
+
copy_html = f"""
|
| 269 |
+
<div style="margin-top: 10px;">
|
| 270 |
+
<button onclick="copyText_{i}()" style="
|
| 271 |
+
background: transparent;
|
| 272 |
+
border: 1px solid rgba(250, 250, 250, 0.2);
|
| 273 |
+
border-radius: 4px;
|
| 274 |
+
cursor: pointer;
|
| 275 |
+
font-size: 1.2rem;
|
| 276 |
+
padding: 0.25rem 0.5rem;
|
| 277 |
+
opacity: 0.7;
|
| 278 |
+
transition: opacity 0.2s;
|
| 279 |
+
" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.7'" title="Copy to clipboard">
|
| 280 |
+
π
|
| 281 |
+
</button>
|
| 282 |
+
<span id="status_{i}" style="margin-left: 10px; color: green; display: none;">β Copied!</span>
|
| 283 |
+
<textarea id="text_{i}" style="position: absolute; left: -9999px;">{escaped_content}</textarea>
|
| 284 |
+
</div>
|
| 285 |
+
|
| 286 |
+
<script>
|
| 287 |
+
function copyText_{i}() {{
|
| 288 |
+
const textarea = document.getElementById('text_{i}');
|
| 289 |
+
textarea.select();
|
| 290 |
+
document.execCommand('copy');
|
| 291 |
+
|
| 292 |
+
// Try modern API as fallback
|
| 293 |
+
if (navigator.clipboard) {{
|
| 294 |
+
navigator.clipboard.writeText(textarea.value);
|
| 295 |
+
}}
|
| 296 |
+
|
| 297 |
+
const status = document.getElementById('status_{i}');
|
| 298 |
+
status.style.display = 'inline';
|
| 299 |
+
setTimeout(() => status.style.display = 'none', 2000);
|
| 300 |
+
}}
|
| 301 |
+
</script>
|
| 302 |
+
"""
|
| 303 |
+
st.components.v1.html(copy_html, height=50)
|
| 304 |
|
| 305 |
# Chat input
|
| 306 |
user_input = st.chat_input("Ask me anything about medical topics...")
|
|
|
|
| 346 |
|
| 347 |
response_placeholder.markdown(full_response)
|
| 348 |
|
| 349 |
+
# Add one-click copy button for the new response
|
| 350 |
+
escaped_content_new = html.escape(full_response)
|
| 351 |
+
|
| 352 |
+
copy_html_new = f"""
|
| 353 |
+
<div style="margin-top: 10px;">
|
| 354 |
+
<button onclick="copyText_new()" style="
|
| 355 |
+
background: transparent;
|
| 356 |
+
border: 1px solid rgba(250, 250, 250, 0.2);
|
| 357 |
+
border-radius: 4px;
|
| 358 |
+
cursor: pointer;
|
| 359 |
+
font-size: 1.2rem;
|
| 360 |
+
padding: 0.25rem 0.5rem;
|
| 361 |
+
opacity: 0.7;
|
| 362 |
+
transition: opacity 0.2s;
|
| 363 |
+
" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.7'" title="Copy to clipboard">
|
| 364 |
+
π
|
| 365 |
+
</button>
|
| 366 |
+
<span id="status_new" style="margin-left: 10px; color: green; display: none;">β Copied!</span>
|
| 367 |
+
<textarea id="text_new" style="position: absolute; left: -9999px;">{escaped_content_new}</textarea>
|
| 368 |
+
</div>
|
| 369 |
+
|
| 370 |
+
<script>
|
| 371 |
+
function copyText_new() {{
|
| 372 |
+
const textarea = document.getElementById('text_new');
|
| 373 |
+
textarea.select();
|
| 374 |
+
document.execCommand('copy');
|
| 375 |
+
|
| 376 |
+
// Try modern API as fallback
|
| 377 |
+
if (navigator.clipboard) {{
|
| 378 |
+
navigator.clipboard.writeText(textarea.value);
|
| 379 |
+
}}
|
| 380 |
+
|
| 381 |
+
const status = document.getElementById('status_new');
|
| 382 |
+
status.style.display = 'inline';
|
| 383 |
+
setTimeout(() => status.style.display = 'none', 2000);
|
| 384 |
+
}}
|
| 385 |
+
</script>
|
| 386 |
+
"""
|
| 387 |
+
st.components.v1.html(copy_html_new, height=50)
|
| 388 |
|
| 389 |
# Save assistant response
|
| 390 |
st.session_state.chat_history.append({
|