Rulga commited on
Commit
56fd21a
·
verified ·
1 Parent(s): ed07e8e

Update app.py

Browse files

init st.session_state

Files changed (1) hide show
  1. app.py +209 -199
app.py CHANGED
@@ -1,200 +1,210 @@
1
- import os
2
- import time
3
- import json
4
- import traceback
5
- from datetime import datetime
6
- import streamlit as st
7
- from dotenv import load_dotenv
8
- from langchain_groq import ChatGroq
9
- from langchain_huggingface import HuggingFaceEmbeddings
10
- from langchain_community.vectorstores import FAISS
11
- from langchain_text_splitters import RecursiveCharacterTextSplitter
12
- from langchain_community.document_loaders import WebBaseLoader
13
- from langchain_core.prompts import PromptTemplate
14
- from langchain_core.output_parsers import StrOutputParser
15
-
16
- # Initialize environment variables
17
- load_dotenv()
18
-
19
- # --------------- Enhanced Logging System ---------------
20
- def log_interaction(user_input: str, bot_response: str, context: str):
21
- """Log user interactions with context and error handling"""
22
- try:
23
- log_entry = {
24
- "timestamp": datetime.now().isoformat(),
25
- "user_input": user_input,
26
- "bot_response": bot_response,
27
- "context": context,
28
- "model": "llama-3.3-70b-versatile",
29
- "kb_version": st.session_state.kb_info.get('version', '1.0')
30
- }
31
-
32
- os.makedirs("chat_history", exist_ok=True)
33
- log_path = os.path.join("chat_history", "chat_logs.json")
34
-
35
- # Atomic write operation with UTF-8 encoding
36
- with open(log_path, "a", encoding="utf-8") as f:
37
- f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")
38
-
39
- except Exception as e:
40
- error_msg = f"Logging error: {str(e)}\n{traceback.format_exc()}"
41
- print(error_msg)
42
- st.error("Error saving interaction log. Please contact support.")
43
-
44
- # --------------- Page Configuration ---------------
45
- st.set_page_config(
46
- page_title="Status Law Assistant",
47
- page_icon="⚖️",
48
- layout="wide",
49
- menu_items={
50
- 'About': "### Legal AI Assistant powered by Status.Law"
51
- }
52
- )
53
-
54
- # --------------- Knowledge Base Management ---------------
55
- VECTOR_STORE_PATH = "vector_store"
56
- URLS = [
57
- "https://status.law",
58
- "https://status.law/about",
59
- "https://status.law/careers",
60
- "https://status.law/tariffs-for-services-of-protection-against-extradition",
61
- "https://status.law/challenging-sanctions",
62
- "https://status.law/law-firm-contact-legal-protection"
63
- "https://status.law/cross-border-banking-legal-issues",
64
- "https://status.law/extradition-defense",
65
- "https://status.law/international-prosecution-protection",
66
- "https://status.law/interpol-red-notice-removal",
67
- "https://status.law/practice-areas",
68
- "https://status.law/reputation-protection",
69
- "https://status.law/faq"
70
- ]
71
-
72
- def init_models():
73
- """Initialize AI models with caching"""
74
- llm = ChatGroq(
75
- model_name="llama-3.3-70b-versatile",
76
- temperature=0.6,
77
- api_key=os.getenv("GROQ_API_KEY")
78
- )
79
- embeddings = HuggingFaceEmbeddings(
80
- model_name="intfloat/multilingual-e5-large-instruct"
81
- )
82
- return llm, embeddings
83
-
84
- def build_knowledge_base(embeddings):
85
- """Create or update the vector knowledge base"""
86
- start_time = time.time()
87
-
88
- documents = []
89
- with st.status("Building knowledge base..."):
90
- for url in URLS:
91
- try:
92
- loader = WebBaseLoader(url)
93
- documents.extend(loader.load())
94
- except Exception as e:
95
- st.error(f"Failed to load {url}: {str(e)}")
96
-
97
- text_splitter = RecursiveCharacterTextSplitter(
98
- chunk_size=500,
99
- chunk_overlap=100
100
- )
101
- chunks = text_splitter.split_documents(documents)
102
-
103
- vector_store = FAISS.from_documents(chunks, embeddings)
104
- vector_store.save_local(VECTOR_STORE_PATH)
105
-
106
- # Update version information
107
- st.session_state.kb_info.update({
108
- 'build_time': time.time() - start_time,
109
- 'size': sum(os.path.getsize(f) for f in os.listdir(VECTOR_STORE_PATH)) / (1024 ** 2),
110
- 'version': datetime.now().strftime("%Y%m%d-%H%M%S")
111
- })
112
-
113
- return vector_store
114
-
115
- # --------------- Chat Interface ---------------
116
- def main():
117
- llm, embeddings = init_models()
118
-
119
- # Initialize or load knowledge base
120
- if not os.path.exists(VECTOR_STORE_PATH):
121
- if st.button("Initialize Knowledge Base"):
122
- with st.spinner("Creating knowledge base..."):
123
- st.session_state.vector_store = build_knowledge_base(embeddings)
124
- st.rerun()
125
- return
126
-
127
- if 'vector_store' not in st.session_state:
128
- st.session_state.vector_store = FAISS.load_local(
129
- VECTOR_STORE_PATH, embeddings, allow_dangerous_deserialization=True
130
- )
131
-
132
- # Display chat history
133
- if 'messages' not in st.session_state:
134
- st.session_state.messages = []
135
-
136
- for msg in st.session_state.messages:
137
- st.chat_message(msg["role"]).write(msg["content"])
138
-
139
- # Process user input
140
- if user_input := st.chat_input("Ask your legal question"):
141
- # Display user message
142
- st.chat_message("user").write(user_input)
143
-
144
- with st.chat_message("assistant"):
145
- with st.spinner("Analyzing your question..."):
146
- try:
147
- # Retrieve relevant context
148
- context_docs = st.session_state.vector_store.similarity_search(user_input)
149
- context_text = "\n".join(d.page_content for d in context_docs)
150
-
151
- # Generate response
152
- prompt_template = PromptTemplate.from_template("""
153
- You are a helpful and polite legal assistant at Status Law.
154
- You answer in the language in which the question was asked.
155
- Answer the question based on the context provided.
156
- If you cannot answer based on the context, say so politely and offer to contact Status Law directly via the following channels:
157
- - For all users: +32465594521 (landline phone).
158
- - For English and Swedish speakers only: +46728495129 (available on WhatsApp, Telegram, Signal, IMO).
159
- - Provide a link to the contact form: [Contact Form](https://status.law/law-firm-contact-legal-protection/).
160
- If the user has questions about specific services and their costs, suggest they visit the page https://status.law/tariffs-for-services-of-protection-against-extradition-and-international-prosecution/ for detailed information.
161
-
162
- Ask the user additional questions to understand which service to recommend and provide an estimated cost. For example, clarify their situation and needs to suggest the most appropriate options.
163
-
164
- Also, offer free consultations if they are available and suitable for the user's request.
165
- Answer professionally but in a friendly manner.
166
-
167
- Example:
168
- Q: How can I challenge the sanctions?
169
- A: To challenge the sanctions, you should consult with our legal team, who specialize in this area. Please contact us directly for detailed advice. You can fill out our contact form here: [Contact Form](https://status.law/law-firm-contact-legal-protection/).
170
-
171
- Context: {context}
172
- Question: {question}
173
-
174
- Response Guidelines:
175
- 1. Answer in the user's language
176
- 2. Cite sources when possible
177
- 3. Offer contact options if unsure
178
- """)
179
-
180
- response = (prompt_template | llm | StrOutputParser()).invoke({
181
- "context": context_text,
182
- "question": user_input
183
- })
184
-
185
- # Display and log interaction
186
- st.write(response)
187
- log_interaction(user_input, response, context_text)
188
- st.session_state.messages.extend([
189
- {"role": "user", "content": user_input},
190
- {"role": "assistant", "content": response}
191
- ])
192
-
193
- except Exception as e:
194
- error_msg = f"Processing error: {str(e)}\n{traceback.format_exc()}"
195
- st.error("Error processing request. Please try again.")
196
- print(error_msg)
197
- log_interaction(user_input, "SYSTEM_ERROR", context_text)
198
-
199
- if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
200
  main()
 
1
+ import os
2
+ import time
3
+ import streamlit as st
4
+ from dotenv import load_dotenv
5
+ from langchain_groq import ChatGroq
6
+ from langchain_huggingface import HuggingFaceEmbeddings
7
+ from langchain_community.vectorstores import FAISS
8
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
9
+ from langchain_community.document_loaders import WebBaseLoader
10
+ from langchain_core.prompts import PromptTemplate
11
+ from langchain_core.output_parsers import StrOutputParser
12
+ from datetime import datetime
13
+ import json
14
+ import traceback
15
+
16
+ # Initialize environment variables
17
+ load_dotenv()
18
+
19
+ # --------------- Session State Initialization ---------------
20
+ def init_session_state():
21
+ """Initialize all required session state variables"""
22
+ defaults = {
23
+ 'kb_info': {
24
+ 'build_time': None,
25
+ 'size': None,
26
+ 'version': '1.1'
27
+ },
28
+ 'messages': [],
29
+ 'vector_store': None,
30
+ 'models_initialized': False
31
+ }
32
+
33
+ for key, value in defaults.items():
34
+ if key not in st.session_state:
35
+ st.session_state[key] = value
36
+
37
+ # --------------- Enhanced Logging ---------------
38
+ def log_interaction(user_input: str, bot_response: str, context: str):
39
+ """Log interactions with error handling"""
40
+ try:
41
+ log_entry = {
42
+ "timestamp": datetime.now().isoformat(),
43
+ "user_input": user_input,
44
+ "bot_response": bot_response,
45
+ "context": context[:500], # Store first 500 chars of context
46
+ "kb_version": st.session_state.kb_info['version']
47
+ }
48
+
49
+ os.makedirs("chat_history", exist_ok=True)
50
+ log_path = os.path.join("chat_history", "chat_logs.json")
51
+
52
+ with open(log_path, "a", encoding="utf-8") as f:
53
+ f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")
54
+
55
+ except Exception as e:
56
+ st.error(f"Logging error: {str(e)}")
57
+ print(traceback.format_exc())
58
+
59
+ # --------------- Model Initialization ---------------
60
+ @st.cache_resource
61
+ def init_models():
62
+ """Initialize AI models with caching"""
63
+ try:
64
+ llm = ChatGroq(
65
+ model_name="llama-3.3-70b-versatile",
66
+ temperature=0.6,
67
+ api_key=os.getenv("GROQ_API_KEY")
68
+ )
69
+ embeddings = HuggingFaceEmbeddings(
70
+ model_name="intfloat/multilingual-e5-large-instruct"
71
+ )
72
+ st.session_state.models_initialized = True
73
+ return llm, embeddings
74
+ except Exception as e:
75
+ st.error(f"Model initialization failed: {str(e)}")
76
+ st.stop()
77
+
78
+ # --------------- Knowledge Base Management ---------------
79
+ VECTOR_STORE_PATH = "vector_store"
80
+ URLS = [
81
+ "https://status.law",
82
+ "https://status.law/about",
83
+ # ... other URLs ...
84
+ ]
85
+
86
+ def build_knowledge_base(_embeddings):
87
+ """Build or update the knowledge base"""
88
+ try:
89
+ start_time = time.time()
90
+ documents = []
91
+
92
+ with st.status("Building knowledge base..."):
93
+ for url in URLS:
94
+ try:
95
+ loader = WebBaseLoader(url)
96
+ docs = loader.load()
97
+ documents.extend(docs)
98
+ st.write(f"✓ Loaded {url}")
99
+ except Exception as e:
100
+ st.error(f"Failed to load {url}: {str(e)}")
101
+
102
+ text_splitter = RecursiveCharacterTextSplitter(
103
+ chunk_size=500,
104
+ chunk_overlap=100
105
+ )
106
+ chunks = text_splitter.split_documents(documents)
107
+
108
+ vector_store = FAISS.from_documents(chunks, _embeddings)
109
+ vector_store.save_local(VECTOR_STORE_PATH)
110
+
111
+ # Update knowledge base info
112
+ st.session_state.kb_info.update({
113
+ 'build_time': time.time() - start_time,
114
+ 'size': sum(os.path.getsize(f) for f in os.listdir(VECTOR_STORE_PATH)) / (1024 ** 2),
115
+ 'version': datetime.now().strftime("%Y%m%d-%H%M%S")
116
+ })
117
+
118
+ return vector_store
119
+ except Exception as e:
120
+ st.error(f"Knowledge base creation failed: {str(e)}")
121
+ st.stop()
122
+
123
+ # --------------- Main Application ---------------
124
+ def main():
125
+ # Initialize session state first
126
+ init_session_state()
127
+
128
+ # Page configuration
129
+ st.set_page_config(
130
+ page_title="Status Law Assistant",
131
+ page_icon="⚖️",
132
+ layout="wide"
133
+ )
134
+
135
+ # Display header
136
+ st.markdown('''
137
+ <h1 style="border-bottom: 2px solid #444; padding-bottom: 10px;">
138
+ ⚖️ <a href="https://status.law/" style="text-decoration: none; color: #2B5876;">Status.Law</a> Legal Assistant
139
+ </h1>
140
+ ''', unsafe_allow_html=True)
141
+
142
+ # Initialize models
143
+ llm, embeddings = init_models()
144
+
145
+ # Knowledge base initialization
146
+ if not os.path.exists(VECTOR_STORE_PATH):
147
+ st.warning("Knowledge base not initialized")
148
+ if st.button("Create Knowledge Base"):
149
+ st.session_state.vector_store = build_knowledge_base(embeddings)
150
+ st.rerun()
151
+ return
152
+
153
+ if not st.session_state.vector_store:
154
+ try:
155
+ st.session_state.vector_store = FAISS.load_local(
156
+ VECTOR_STORE_PATH,
157
+ embeddings,
158
+ allow_dangerous_deserialization=True
159
+ )
160
+ except Exception as e:
161
+ st.error(f"Failed to load knowledge base: {str(e)}")
162
+ st.stop()
163
+
164
+ # Chat interface
165
+ for message in st.session_state.messages:
166
+ with st.chat_message(message["role"]):
167
+ st.markdown(message["content"])
168
+
169
+ if prompt := st.chat_input("Ask your legal question"):
170
+ # Add user message to chat history
171
+ st.session_state.messages.append({"role": "user", "content": prompt})
172
+ with st.chat_message("user"):
173
+ st.markdown(prompt)
174
+
175
+ # Generate response
176
+ with st.chat_message("assistant"):
177
+ try:
178
+ # Retrieve context
179
+ context_docs = st.session_state.vector_store.similarity_search(prompt)
180
+ context_text = "\n".join([d.page_content for d in context_docs])
181
+
182
+ # Generate response
183
+ prompt_template = PromptTemplate.from_template('''
184
+ You are a helpful and polite legal assistant at Status.Law.
185
+ Answer in the language in which the question was asked.
186
+ Answer the question based on the context provided.
187
+
188
+ Context: {context}
189
+ Question: {question}
190
+ ''')
191
+
192
+ chain = prompt_template | llm | StrOutputParser()
193
+ response = chain.invoke({
194
+ "context": context_text,
195
+ "question": prompt
196
+ })
197
+
198
+ # Display and log
199
+ st.markdown(response)
200
+ log_interaction(prompt, response, context_text)
201
+ st.session_state.messages.append({"role": "assistant", "content": response})
202
+
203
+ except Exception as e:
204
+ error_msg = f"Error generating response: {str(e)}"
205
+ st.error(error_msg)
206
+ log_interaction(prompt, error_msg, "")
207
+ print(traceback.format_exc())
208
+
209
+ if __name__ == "__main__":
210
  main()