Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -13,6 +13,8 @@ from langchain.agents.format_scratchpad.openai_tools import format_to_openai_too
|
|
| 13 |
from langchain_core.messages import AIMessage, HumanMessage
|
| 14 |
from langchain_community.document_loaders import TextLoader
|
| 15 |
from langchain_text_splitters import CharacterTextSplitter
|
|
|
|
|
|
|
| 16 |
import serpapi
|
| 17 |
import requests
|
| 18 |
import streamlit.components.v1 as components
|
|
@@ -106,15 +108,18 @@ def convert_pdf_to_md(file):
|
|
| 106 |
|
| 107 |
def convert_docx_to_md(file):
|
| 108 |
"""
|
| 109 |
-
|
| 110 |
"""
|
| 111 |
try:
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
except Exception as e:
|
| 116 |
-
|
| 117 |
-
return ""
|
| 118 |
|
| 119 |
def convert_txt_to_md(file):
|
| 120 |
"""
|
|
@@ -154,35 +159,47 @@ def merge_markdown_contents(contents):
|
|
| 154 |
return merged_content
|
| 155 |
|
| 156 |
def upload_to_firebase(user_id, file):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
"""
|
| 158 |
-
|
| 159 |
"""
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
| 169 |
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
public_url = storage.child(filename).get_url(None)
|
| 175 |
-
doc_id = str(uuid.uuid4())
|
| 176 |
-
db.child("users").child(user_id).child("documents").child(doc_id).set({
|
| 177 |
-
"name": file.name,
|
| 178 |
-
"content_url": public_url # Link to the file in Firebase Storage
|
| 179 |
-
})
|
| 180 |
-
|
| 181 |
-
st.success(f"File '{file.name}' uploaded successfully!")
|
| 182 |
-
return content,public_url
|
| 183 |
-
except Exception as e:
|
| 184 |
-
st.error(f"Error uploading to Firebase: {e}")
|
| 185 |
-
return None
|
| 186 |
|
| 187 |
|
| 188 |
def fetch_trustbuilders(user_id):
|
|
@@ -407,46 +424,39 @@ def load_main_data_source():
|
|
| 407 |
st.error(f"Error loading main data source: {e}")
|
| 408 |
return []
|
| 409 |
|
| 410 |
-
def combine_data_sources():
|
| 411 |
-
main_data_source = load_main_data_source()
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
trustbuilders = [Document(page_content=tb["message"]) for tb in st.session_state.get("trustbuilders", {}).values()]
|
| 415 |
-
brand_tonalities = [Document(page_content=bt["message"]) for bt in st.session_state.get("brand_tonality", {}).values()]
|
| 416 |
-
|
| 417 |
-
return main_data_source + user_data_source + trustbuilders + brand_tonalities
|
| 418 |
-
|
| 419 |
|
| 420 |
-
def refresh_faiss_index():
|
| 421 |
-
combined_sources = combine_data_sources()
|
| 422 |
-
if combined_sources:
|
| 423 |
-
embeddings = OpenAIEmbeddings()
|
| 424 |
-
db_faiss = FAISS.from_documents(combined_sources, embeddings)
|
| 425 |
-
st.session_state["faiss_db"] = db_faiss
|
| 426 |
-
|
| 427 |
-
def load_user_data_source(user_id):
|
| 428 |
"""
|
| 429 |
-
|
|
|
|
| 430 |
"""
|
| 431 |
-
|
| 432 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
|
| 434 |
-
if not docs:
|
| 435 |
-
|
| 436 |
-
return user_documents
|
| 437 |
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
return user_documents
|
| 450 |
|
| 451 |
|
| 452 |
def update_message_counter():
|
|
@@ -545,13 +555,14 @@ def download_link(content, filename):
|
|
| 545 |
|
| 546 |
|
| 547 |
|
| 548 |
-
|
|
|
|
| 549 |
try:
|
| 550 |
-
docs = db.child("users").child(
|
| 551 |
-
|
| 552 |
except Exception as e:
|
| 553 |
-
st.error(f"Error fetching documents: {e}")
|
| 554 |
-
|
| 555 |
|
| 556 |
|
| 557 |
|
|
@@ -757,17 +768,18 @@ def side():
|
|
| 757 |
st.sidebar.error(f"Error fetching documents: {e}")
|
| 758 |
st.session_state["documents"] = {}
|
| 759 |
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
| 764 |
-
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
|
|
|
| 768 |
st.text_area(
|
| 769 |
label="",
|
| 770 |
-
value=
|
| 771 |
height=150,
|
| 772 |
key="saved_documents_text_area",
|
| 773 |
disabled=True
|
|
@@ -785,7 +797,6 @@ def side():
|
|
| 785 |
{"content": content, "name": uploaded_file.name}
|
| 786 |
)
|
| 787 |
st.session_state["documents"][doc_id] = {"content": content, "name": uploaded_file.name}
|
| 788 |
-
refresh_faiss_index()
|
| 789 |
st.sidebar.success(f"Document '{uploaded_file.name}' uploaded successfully!")
|
| 790 |
st.rerun()
|
| 791 |
else:
|
|
@@ -794,25 +805,30 @@ def side():
|
|
| 794 |
st.sidebar.error(f"Error uploading document: {e}")
|
| 795 |
else:
|
| 796 |
st.sidebar.warning("Please select a file to upload.")
|
| 797 |
-
|
| 798 |
-
# Delete Button
|
| 799 |
if st.session_state["documents"]:
|
| 800 |
-
|
| 801 |
-
|
|
|
|
| 802 |
options=list(st.session_state["documents"].keys()),
|
| 803 |
format_func=lambda x: st.session_state["documents"][x].get("name", f"Document {x}"),
|
| 804 |
-
key="
|
| 805 |
)
|
| 806 |
-
|
|
|
|
|
|
|
| 807 |
try:
|
| 808 |
-
|
| 809 |
-
st.session_state["
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 810 |
st.sidebar.success("Document deleted successfully!")
|
| 811 |
-
st.rerun()
|
| 812 |
except Exception as e:
|
| 813 |
st.sidebar.error(f"Error deleting document: {e}")
|
| 814 |
-
|
| 815 |
-
|
| 816 |
|
| 817 |
st.sidebar.markdown("</div>", unsafe_allow_html=True)
|
| 818 |
trust_buckets = ["Any","Stability", "Development", "Relationship", "Benefit", "Vision", "Competence"]
|
|
@@ -1035,26 +1051,33 @@ def google_search(query):
|
|
| 1035 |
|
| 1036 |
|
| 1037 |
|
| 1038 |
-
# RAG response function
|
| 1039 |
def rag_response(query):
|
| 1040 |
try:
|
| 1041 |
-
#
|
| 1042 |
-
|
| 1043 |
-
|
| 1044 |
-
|
| 1045 |
-
|
| 1046 |
-
|
| 1047 |
-
llm = ChatOpenAI(model="gpt-4o", temperature=0.5, api_key=openai_api_key)
|
| 1048 |
-
response = llm.invoke(prompt)
|
| 1049 |
-
|
| 1050 |
-
# Replace terms in the final output as per your restrictions
|
| 1051 |
-
response_content = response.content
|
| 1052 |
|
| 1053 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1054 |
except Exception as e:
|
| 1055 |
logger.error(f"Error generating RAG response: {e}")
|
| 1056 |
return "Error occurred during RAG response generation"
|
| 1057 |
|
|
|
|
| 1058 |
# Define tools
|
| 1059 |
@tool
|
| 1060 |
def knowledge_base_tool(query: str):
|
|
@@ -1308,7 +1331,15 @@ prompt_template = ChatPromptTemplate.from_messages([
|
|
| 1308 |
])
|
| 1309 |
|
| 1310 |
# Create Langchain Agent
|
| 1311 |
-
llm = ChatOpenAI(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1312 |
llm_with_tools = llm.bind_tools(tools)
|
| 1313 |
|
| 1314 |
# Define the agent pipeline
|
|
@@ -1626,13 +1657,21 @@ def handle_memory_queries(prompt):
|
|
| 1626 |
"""
|
| 1627 |
prompt = prompt.lower().strip()
|
| 1628 |
|
| 1629 |
-
|
| 1630 |
-
|
| 1631 |
-
|
| 1632 |
-
|
| 1633 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1634 |
else:
|
| 1635 |
-
assistant_response = "
|
| 1636 |
|
| 1637 |
# Save response to chat history and display it
|
| 1638 |
st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
|
|
@@ -1640,6 +1679,41 @@ def handle_memory_queries(prompt):
|
|
| 1640 |
st.markdown(assistant_response)
|
| 1641 |
return None
|
| 1642 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1643 |
# Show saved TrustBuilders
|
| 1644 |
elif "find my saved trustbuilders" in prompt or "show my saved trustbuilders" in prompt:
|
| 1645 |
trustbuilders = fetch_trustbuilders(st.session_state.get("wix_user_id", "default_user"))
|
|
@@ -1752,9 +1826,90 @@ def handle_save_trustbuilder(content, specified_bucket=None):
|
|
| 1752 |
|
| 1753 |
|
| 1754 |
|
| 1755 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1756 |
|
| 1757 |
-
# Function to update the message counter in a static location
|
| 1758 |
|
| 1759 |
if "email" not in st.session_state:
|
| 1760 |
st.session_state["email"] = f"demo_user_{st.session_state['wix_user_id']}@example.com"
|
|
|
|
| 13 |
from langchain_core.messages import AIMessage, HumanMessage
|
| 14 |
from langchain_community.document_loaders import TextLoader
|
| 15 |
from langchain_text_splitters import CharacterTextSplitter
|
| 16 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
| 17 |
+
|
| 18 |
import serpapi
|
| 19 |
import requests
|
| 20 |
import streamlit.components.v1 as components
|
|
|
|
| 108 |
|
| 109 |
def convert_docx_to_md(file):
|
| 110 |
"""
|
| 111 |
+
Extract text from a .docx file and return as a single string.
|
| 112 |
"""
|
| 113 |
try:
|
| 114 |
+
# Read the file
|
| 115 |
+
doc = DocxDocument(uploaded_file)
|
| 116 |
+
# Extract all text
|
| 117 |
+
text = "\n".join([paragraph.text for paragraph in doc.paragraphs])
|
| 118 |
+
if not text.strip(): # Handle empty content
|
| 119 |
+
raise ValueError("The document has no content.")
|
| 120 |
+
return text
|
| 121 |
except Exception as e:
|
| 122 |
+
raise ValueError(f"Error reading .docx file: {e}")
|
|
|
|
| 123 |
|
| 124 |
def convert_txt_to_md(file):
|
| 125 |
"""
|
|
|
|
| 159 |
return merged_content
|
| 160 |
|
| 161 |
def upload_to_firebase(user_id, file):
|
| 162 |
+
content = convert_file_to_md(file)
|
| 163 |
+
if not content:
|
| 164 |
+
return None, "Failed to convert file to content."
|
| 165 |
+
|
| 166 |
+
doc_id = str(uuid.uuid4())
|
| 167 |
+
document_data = {"content": content, "name": file.name}
|
| 168 |
+
|
| 169 |
+
# Save to Firebase
|
| 170 |
+
db.child("users").child(user_id).child("KnowledgeBase").child(doc_id).set(document_data)
|
| 171 |
+
|
| 172 |
+
# Update session state
|
| 173 |
+
if "documents" not in st.session_state:
|
| 174 |
+
st.session_state["documents"] = {}
|
| 175 |
+
st.session_state["documents"][doc_id] = document_data
|
| 176 |
+
|
| 177 |
+
# Index the document content
|
| 178 |
+
index_document_content(content, doc_id)
|
| 179 |
+
|
| 180 |
+
st.sidebar.success(f"Document '{file.name}' uploaded successfully!")
|
| 181 |
+
return content,None
|
| 182 |
+
|
| 183 |
+
def index_document_content(doc_content, doc_id):
|
| 184 |
"""
|
| 185 |
+
Indexes the document content by splitting it into chunks and creating embeddings.
|
| 186 |
"""
|
| 187 |
+
# Split the document into chunks
|
| 188 |
+
text_splitter = RecursiveCharacterTextSplitter(
|
| 189 |
+
chunk_size=500,
|
| 190 |
+
chunk_overlap=50,
|
| 191 |
+
)
|
| 192 |
+
texts = text_splitter.split_text(doc_content)
|
| 193 |
|
| 194 |
+
# Create embeddings for each chunk
|
| 195 |
+
embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
|
| 196 |
+
doc_metadata = [{"doc_id": doc_id, "chunk_id": i} for i in range(len(texts))]
|
| 197 |
+
vector_store = FAISS.from_texts(texts, embeddings, metadatas=doc_metadata)
|
| 198 |
|
| 199 |
+
# Save the vector store in session state
|
| 200 |
+
if "vector_store" not in st.session_state:
|
| 201 |
+
st.session_state["vector_store"] = {}
|
| 202 |
+
st.session_state["vector_store"][doc_id] = vector_store
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
|
| 204 |
|
| 205 |
def fetch_trustbuilders(user_id):
|
|
|
|
| 424 |
st.error(f"Error loading main data source: {e}")
|
| 425 |
return []
|
| 426 |
|
| 427 |
+
def combine_data_sources(include_main=True):
|
| 428 |
+
main_data_source = load_main_data_source() if include_main else []
|
| 429 |
+
user_documents = load_user_data_source(st.session_state["wix_user_id"])
|
| 430 |
+
return main_data_source + user_documents
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
|
| 432 |
+
def refresh_faiss_index(documents=None):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
"""
|
| 434 |
+
Refresh the FAISS index with updated documents.
|
| 435 |
+
If documents are provided, only update those; otherwise, rebuild the index.
|
| 436 |
"""
|
| 437 |
+
if documents:
|
| 438 |
+
# Add/Update specific documents in the index
|
| 439 |
+
embeddings = OpenAIEmbeddings()
|
| 440 |
+
st.session_state["faiss_db"].add_documents(documents, embeddings)
|
| 441 |
+
else:
|
| 442 |
+
# Rebuild the entire index
|
| 443 |
+
combined_sources = combine_data_sources()
|
| 444 |
+
if combined_sources:
|
| 445 |
+
embeddings = OpenAIEmbeddings()
|
| 446 |
+
st.session_state["faiss_db"] = FAISS.from_documents(combined_sources, embeddings)
|
| 447 |
|
|
|
|
|
|
|
|
|
|
| 448 |
|
| 449 |
+
|
| 450 |
+
def load_user_data_source(user_id):
|
| 451 |
+
try:
|
| 452 |
+
docs = db.child("users").child(user_id).child("KnowledgeBase").get().val()
|
| 453 |
+
if not docs:
|
| 454 |
+
return []
|
| 455 |
+
user_documents = [Document(page_content=doc["content"]) for doc in docs.values()]
|
| 456 |
+
return user_documents
|
| 457 |
+
except Exception as e:
|
| 458 |
+
st.error(f"Error loading user data source: {e}")
|
| 459 |
+
return []
|
|
|
|
| 460 |
|
| 461 |
|
| 462 |
def update_message_counter():
|
|
|
|
| 555 |
|
| 556 |
|
| 557 |
|
| 558 |
+
|
| 559 |
+
def fetch_documents():
|
| 560 |
try:
|
| 561 |
+
docs = db.child("users").child(st.session_state["wix_user_id"]).child("KnowledgeBase").get().val()
|
| 562 |
+
st.session_state["documents"] = docs if docs else {}
|
| 563 |
except Exception as e:
|
| 564 |
+
st.sidebar.error(f"Error fetching documents: {e}")
|
| 565 |
+
st.session_state["documents"] = {}
|
| 566 |
|
| 567 |
|
| 568 |
|
|
|
|
| 768 |
st.sidebar.error(f"Error fetching documents: {e}")
|
| 769 |
st.session_state["documents"] = {}
|
| 770 |
|
| 771 |
+
def update_saved_docs_content():
|
| 772 |
+
return "\n\n---\n\n".join(
|
| 773 |
+
[
|
| 774 |
+
f"**{doc_data.get('name', f'Document {doc_id[:8]}')}**\n{doc_data.get('content', 'No content available')}"
|
| 775 |
+
for doc_id, doc_data in st.session_state["documents"].items()
|
| 776 |
+
]
|
| 777 |
+
) if st.session_state["documents"] else "Save documents like your brand tonality, key phrases, or segments here and they will show here."
|
| 778 |
+
saved_docs_content = update_saved_docs_content()
|
| 779 |
+
|
| 780 |
st.text_area(
|
| 781 |
label="",
|
| 782 |
+
value=saved_docs_content,
|
| 783 |
height=150,
|
| 784 |
key="saved_documents_text_area",
|
| 785 |
disabled=True
|
|
|
|
| 797 |
{"content": content, "name": uploaded_file.name}
|
| 798 |
)
|
| 799 |
st.session_state["documents"][doc_id] = {"content": content, "name": uploaded_file.name}
|
|
|
|
| 800 |
st.sidebar.success(f"Document '{uploaded_file.name}' uploaded successfully!")
|
| 801 |
st.rerun()
|
| 802 |
else:
|
|
|
|
| 805 |
st.sidebar.error(f"Error uploading document: {e}")
|
| 806 |
else:
|
| 807 |
st.sidebar.warning("Please select a file to upload.")
|
| 808 |
+
# Display and delete functionality for documents
|
|
|
|
| 809 |
if st.session_state["documents"]:
|
| 810 |
+
# Select a document to view or delete
|
| 811 |
+
selected_doc_id = st.selectbox(
|
| 812 |
+
"Select document to view or delete",
|
| 813 |
options=list(st.session_state["documents"].keys()),
|
| 814 |
format_func=lambda x: st.session_state["documents"][x].get("name", f"Document {x}"),
|
| 815 |
+
key="select_doc"
|
| 816 |
)
|
| 817 |
+
|
| 818 |
+
# Button to delete the selected document
|
| 819 |
+
if st.sidebar.button("Delete ", key="delete_button"):
|
| 820 |
try:
|
| 821 |
+
# Remove the document from Firebase
|
| 822 |
+
db.child("users").child(st.session_state["wix_user_id"]).child("KnowledgeBase").child(selected_doc_id).remove()
|
| 823 |
+
|
| 824 |
+
# Remove the document from session state
|
| 825 |
+
fetch_documents()
|
| 826 |
+
|
| 827 |
+
|
| 828 |
+
|
| 829 |
st.sidebar.success("Document deleted successfully!")
|
|
|
|
| 830 |
except Exception as e:
|
| 831 |
st.sidebar.error(f"Error deleting document: {e}")
|
|
|
|
|
|
|
| 832 |
|
| 833 |
st.sidebar.markdown("</div>", unsafe_allow_html=True)
|
| 834 |
trust_buckets = ["Any","Stability", "Development", "Relationship", "Benefit", "Vision", "Competence"]
|
|
|
|
| 1051 |
|
| 1052 |
|
| 1053 |
|
|
|
|
| 1054 |
def rag_response(query):
|
| 1055 |
try:
|
| 1056 |
+
# Check if the query references uploaded documents
|
| 1057 |
+
if "using uploaded document" in query.lower():
|
| 1058 |
+
document_response = handle_document_query(query) # Use your existing `handle_document_query` function
|
| 1059 |
+
if document_response:
|
| 1060 |
+
return document_response
|
| 1061 |
+
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1062 |
|
| 1063 |
+
# Proceed with the existing knowledge base logic if no uploaded document context is specified
|
| 1064 |
+
retrieved_docs = search_knowledge_base(query)
|
| 1065 |
+
context = "\n".join(doc.page_content for doc in retrieved_docs)
|
| 1066 |
+
|
| 1067 |
+
# Prepare the prompt with the retrieved context
|
| 1068 |
+
prompt = f"Context:\n{context}\n\nQuestion: {query}\nAnswer:"
|
| 1069 |
+
llm = ChatOpenAI(model="gpt-4o", temperature=0.5, api_key=openai_api_key)
|
| 1070 |
+
response = llm.invoke(prompt)
|
| 1071 |
+
|
| 1072 |
+
# Replace terms in the final output as per your restrictions
|
| 1073 |
+
response_content = response.content
|
| 1074 |
+
|
| 1075 |
+
return response_content
|
| 1076 |
except Exception as e:
|
| 1077 |
logger.error(f"Error generating RAG response: {e}")
|
| 1078 |
return "Error occurred during RAG response generation"
|
| 1079 |
|
| 1080 |
+
|
| 1081 |
# Define tools
|
| 1082 |
@tool
|
| 1083 |
def knowledge_base_tool(query: str):
|
|
|
|
| 1331 |
])
|
| 1332 |
|
| 1333 |
# Create Langchain Agent
|
| 1334 |
+
llm = ChatOpenAI(
|
| 1335 |
+
model="gpt-4o",
|
| 1336 |
+
temperature=0.7, # Balanced creativity and adherence
|
| 1337 |
+
max_tokens=2000, # Ensure sufficient output length
|
| 1338 |
+
top_p=0.85, # Focused outputs
|
| 1339 |
+
frequency_penalty=0.1, # Minimize repetition
|
| 1340 |
+
presence_penalty=0.7 # Moderate novelty to maintain adherence
|
| 1341 |
+
)
|
| 1342 |
+
|
| 1343 |
llm_with_tools = llm.bind_tools(tools)
|
| 1344 |
|
| 1345 |
# Define the agent pipeline
|
|
|
|
| 1657 |
"""
|
| 1658 |
prompt = prompt.lower().strip()
|
| 1659 |
|
| 1660 |
+
valid_buckets = ["Stability", "Development", "Relationship", "Benefit", "Vision", "Competence"]
|
| 1661 |
+
|
| 1662 |
+
# Case 1: Save this as [bucket] trust builder: [content]
|
| 1663 |
+
match_save_this_specific = re.search(r"\bsave\s+(this\s+)?as\s+(\w+)\s+trust\s+builders?\s*:\s*(.+)", prompt, re.IGNORECASE)
|
| 1664 |
+
if match_save_this_specific:
|
| 1665 |
+
specified_bucket = match_save_this_specific.group(2).capitalize()
|
| 1666 |
+
content_to_save = match_save_this_specific.group(3).strip()
|
| 1667 |
+
|
| 1668 |
+
if specified_bucket in valid_buckets:
|
| 1669 |
+
if content_to_save:
|
| 1670 |
+
assistant_response = handle_save_trustbuilder(content_to_save, specified_bucket)
|
| 1671 |
+
else:
|
| 1672 |
+
assistant_response = "No content provided. Please include content after 'save this as [bucket] trust builder:'."
|
| 1673 |
else:
|
| 1674 |
+
assistant_response = f"Invalid Trust Bucket '{specified_bucket}'. Valid buckets are: {', '.join(valid_buckets)}."
|
| 1675 |
|
| 1676 |
# Save response to chat history and display it
|
| 1677 |
st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
|
|
|
|
| 1679 |
st.markdown(assistant_response)
|
| 1680 |
return None
|
| 1681 |
|
| 1682 |
+
# Case 2: Save this under [bucket]: [content]
|
| 1683 |
+
match_save_under_specific = re.search(r"\bsave\s+(this\s+)?under\s+(\w+)\s*:\s*(.+)", prompt, re.IGNORECASE)
|
| 1684 |
+
if match_save_under_specific:
|
| 1685 |
+
specified_bucket = match_save_under_specific.group(2).capitalize()
|
| 1686 |
+
content_to_save = match_save_under_specific.group(3).strip()
|
| 1687 |
+
|
| 1688 |
+
if specified_bucket in valid_buckets:
|
| 1689 |
+
if content_to_save:
|
| 1690 |
+
assistant_response = handle_save_trustbuilder(content_to_save, specified_bucket)
|
| 1691 |
+
else:
|
| 1692 |
+
assistant_response = "No content provided. Please include content after 'save this under [bucket]:'."
|
| 1693 |
+
else:
|
| 1694 |
+
assistant_response = f"Invalid Trust Bucket '{specified_bucket}'. Valid buckets are: {', '.join(valid_buckets)}."
|
| 1695 |
+
|
| 1696 |
+
# Save response to chat history and display it
|
| 1697 |
+
st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
|
| 1698 |
+
with st.chat_message("assistant"):
|
| 1699 |
+
st.markdown(assistant_response)
|
| 1700 |
+
return None
|
| 1701 |
+
|
| 1702 |
+
# Case 3: Save and allocate: [content] (automatic allocation)
|
| 1703 |
+
match_save_allocate_auto = re.search(r"\bsave\s+(this\s+)?and\s+allocate\s*:\s*(.+)", prompt, re.IGNORECASE)
|
| 1704 |
+
if match_save_allocate_auto:
|
| 1705 |
+
content_to_save = match_save_allocate_auto.group(2).strip()
|
| 1706 |
+
if content_to_save:
|
| 1707 |
+
assistant_response = handle_save_trustbuilder(content_to_save) # Automatically allocate bucket
|
| 1708 |
+
else:
|
| 1709 |
+
assistant_response = "No content provided. Please include content after 'save and allocate:'."
|
| 1710 |
+
|
| 1711 |
+
# Save response to chat history and display it
|
| 1712 |
+
st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
|
| 1713 |
+
with st.chat_message("assistant"):
|
| 1714 |
+
st.markdown(assistant_response)
|
| 1715 |
+
return
|
| 1716 |
+
|
| 1717 |
# Show saved TrustBuilders
|
| 1718 |
elif "find my saved trustbuilders" in prompt or "show my saved trustbuilders" in prompt:
|
| 1719 |
trustbuilders = fetch_trustbuilders(st.session_state.get("wix_user_id", "default_user"))
|
|
|
|
| 1826 |
|
| 1827 |
|
| 1828 |
|
| 1829 |
+
|
| 1830 |
+
def load_user_memory(user_id):
|
| 1831 |
+
"""
|
| 1832 |
+
Load saved TrustBuilders and uploaded documents from Firebase into session state.
|
| 1833 |
+
"""
|
| 1834 |
+
try:
|
| 1835 |
+
# Load TrustBuilders
|
| 1836 |
+
trustbuilders = db.child("users").child(user_id).child("TrustBuilders").get().val()
|
| 1837 |
+
st.session_state["trustbuilders"] = trustbuilders if trustbuilders else []
|
| 1838 |
+
|
| 1839 |
+
# Load Uploaded Documents from 'KnowledgeBase'
|
| 1840 |
+
documents = db.child("users").child(user_id).child("KnowledgeBase").get().val()
|
| 1841 |
+
st.session_state["documents"] = documents if documents else {}
|
| 1842 |
+
|
| 1843 |
+
# Reconstruct vector stores for each document
|
| 1844 |
+
st.session_state["vector_store"] = {}
|
| 1845 |
+
for doc_id, doc_data in st.session_state["documents"].items():
|
| 1846 |
+
content = doc_data.get("content", "")
|
| 1847 |
+
if content:
|
| 1848 |
+
index_document_content(content, doc_id)
|
| 1849 |
+
|
| 1850 |
+
except Exception as e:
|
| 1851 |
+
st.error(f"Error loading user memory: {e}")
|
| 1852 |
+
st.session_state["trustbuilders"] = []
|
| 1853 |
+
st.session_state["documents"] = {}
|
| 1854 |
+
st.session_state["vector_store"] = {}
|
| 1855 |
+
|
| 1856 |
+
def get_document_content(doc_name=None):
|
| 1857 |
+
documents = st.session_state.get("documents", {})
|
| 1858 |
+
if not documents:
|
| 1859 |
+
return None, "No documents have been uploaded."
|
| 1860 |
+
|
| 1861 |
+
# If a specific document name is provided
|
| 1862 |
+
if doc_name:
|
| 1863 |
+
for doc_id, doc_data in documents.items():
|
| 1864 |
+
if doc_data.get("name", "").lower() == doc_name.lower():
|
| 1865 |
+
content = doc_data.get("content")
|
| 1866 |
+
if content:
|
| 1867 |
+
return content, None
|
| 1868 |
+
else:
|
| 1869 |
+
return None, f"Document '{doc_name}' does not contain any content."
|
| 1870 |
+
return None, f"Document '{doc_name}' not found."
|
| 1871 |
+
|
| 1872 |
+
# Default to the most recent document
|
| 1873 |
+
last_doc = list(documents.values())[-1]
|
| 1874 |
+
content = last_doc.get("content")
|
| 1875 |
+
if content:
|
| 1876 |
+
return content, None
|
| 1877 |
+
else:
|
| 1878 |
+
return None, "The most recently uploaded document does not contain any content."
|
| 1879 |
+
|
| 1880 |
+
def handle_document_query(query):
|
| 1881 |
+
"""
|
| 1882 |
+
Handle queries related to uploaded documents for response generation.
|
| 1883 |
+
"""
|
| 1884 |
+
# Extract specific document name if mentioned
|
| 1885 |
+
doc_name_match = re.search(r"document\s+'([^']+)'", query, re.IGNORECASE)
|
| 1886 |
+
doc_name = doc_name_match.group(1) if doc_name_match else None
|
| 1887 |
+
|
| 1888 |
+
# Fetch document content
|
| 1889 |
+
doc_content, error = get_document_content(doc_name)
|
| 1890 |
+
if error:
|
| 1891 |
+
return error
|
| 1892 |
+
|
| 1893 |
+
# Generate AI response with document context
|
| 1894 |
+
full_prompt = f"Document Content:\n{doc_content}\n\nUser Query: {query}\n\nResponse:"
|
| 1895 |
+
try:
|
| 1896 |
+
llm = ChatOpenAI(model="gpt-4", temperature=0.5, api_key=openai_api_key)
|
| 1897 |
+
response = llm.invoke(full_prompt)
|
| 1898 |
+
return response.content
|
| 1899 |
+
except Exception as e:
|
| 1900 |
+
return f"Error generating response using the document: {e}"
|
| 1901 |
+
|
| 1902 |
+
|
| 1903 |
+
|
| 1904 |
+
|
| 1905 |
+
|
| 1906 |
+
if "missing_trustbucket_content" not in st.session_state:
|
| 1907 |
+
st.session_state["missing_trustbucket_content"] = None
|
| 1908 |
+
|
| 1909 |
+
if "handled" not in st.session_state:
|
| 1910 |
+
st.session_state["handled"] = False
|
| 1911 |
+
|
| 1912 |
|
|
|
|
| 1913 |
|
| 1914 |
if "email" not in st.session_state:
|
| 1915 |
st.session_state["email"] = f"demo_user_{st.session_state['wix_user_id']}@example.com"
|