Rulga commited on
Commit
ed07e8e
·
verified ·
1 Parent(s): 785ef60

Upload 10 files

Browse files
Files changed (10) hide show
  1. .gitignore +6 -0
  2. README.md +15 -10
  3. api/analysis.py +90 -0
  4. api/main.py +19 -0
  5. app - Copy.py +242 -0
  6. app.py +200 -0
  7. gitattributes +44 -0
  8. gitignore +4 -0
  9. requirements.txt +21 -0
  10. run.sh +5 -0
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ /.streamlit
2
+ *.env
3
+ .env
4
+ venv
5
+ .streamlit/secrets.toml
6
+
README.md CHANGED
@@ -1,10 +1,15 @@
1
- ---
2
- title: Doc Chat
3
- emoji: 💻
4
- colorFrom: gray
5
- colorTo: gray
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
1
+ ---
2
+ title: LS Chatbot Log
3
+ emoji: 🌍
4
+ colorFrom: blue
5
+ colorTo: blue
6
+ sdk: streamlit
7
+ sdk_version: 1.42.0
8
+ app_file: app.py
9
+ pinned: false
10
+ short_description: It is a chat built with an AI model about www.Status.law
11
+ ---
12
+
13
+ # LS Chatbot Log
14
+
15
+ It is a chat app built using Streamlit that allows users to interact with an AI model to communicate about www.Status.law
api/analysis.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # analysis.py
2
+ import json
3
+ import pandas as pd
4
+ from collections import defaultdict
5
+ from typing import List, Dict
6
+ from datetime import datetime
7
+
8
+ class LogAnalyzer:
9
+ def __init__(self, log_path: str = "chat_history/chat_logs.json"):
10
+ self.log_path = log_path
11
+ self.logs = self._load_logs()
12
+
13
+ def _load_logs(self) -> List[Dict]:
14
+ """Load and parse log entries from JSON file"""
15
+ try:
16
+ with open(self.log_path, "r", encoding="utf-8") as f:
17
+ return [json.loads(line) for line in f]
18
+ except (FileNotFoundError, json.JSONDecodeError):
19
+ return []
20
+
21
+ def get_basic_stats(self) -> Dict:
22
+ """Calculate basic conversation statistics"""
23
+ if not self.logs:
24
+ return {}
25
+
26
+ return {
27
+ "total_interactions": len(self.logs),
28
+ "unique_users": len({log.get('session_id') for log in self.logs}),
29
+ "avg_response_length": pd.Series([len(log['bot_response']) for log in self.logs]).mean(),
30
+ "most_common_questions": self._get_common_questions(),
31
+ "knowledge_base_usage": self._calculate_kb_usage()
32
+ }
33
+
34
+ def _get_common_questions(self, top_n: int = 5) -> List[Dict]:
35
+ """Identify most frequent user questions"""
36
+ question_counts = defaultdict(int)
37
+ for log in self.logs:
38
+ question_counts[log['user_input']] += 1
39
+ return sorted(
40
+ [{"question": k, "count": v} for k, v in question_counts.items()],
41
+ key=lambda x: x["count"],
42
+ reverse=True
43
+ )[:top_n]
44
+
45
+ def _calculate_kb_usage(self) -> Dict:
46
+ """Analyze knowledge base effectiveness"""
47
+ context_usage = defaultdict(int)
48
+ for log in self.logs:
49
+ if log.get('context'):
50
+ context_usage['with_context'] += 1
51
+ else:
52
+ context_usage['without_context'] += 1
53
+ return context_usage
54
+
55
+ def temporal_analysis(self) -> Dict:
56
+ """Analyze usage patterns over time"""
57
+ df = pd.DataFrame(self.logs)
58
+ df['timestamp'] = pd.to_datetime(df['timestamp'])
59
+
60
+ return {
61
+ "daily_activity": df.resample('D', on='timestamp').size().to_dict(),
62
+ "hourly_pattern": df.groupby(df['timestamp'].dt.hour).size().to_dict()
63
+ }
64
+
65
+ def generate_report(self) -> str:
66
+ """Generate comprehensive analysis report"""
67
+ stats = self.get_basic_stats()
68
+ temporal = self.temporal_analysis()
69
+
70
+ report = f"""
71
+ Legal Assistant Usage Report
72
+ ----------------------------
73
+ Period: {self.logs[0]['timestamp']} - {self.logs[-1]['timestamp']}
74
+
75
+ Total Interactions: {stats['total_interactions']}
76
+ Unique Users: {stats['unique_users']}
77
+ Average Response Length: {stats['avg_response_length']:.1f} chars
78
+
79
+ Top Questions:
80
+ {''.join(f"{q['question']}: {q['count']}\n" for q in stats['most_common_questions'])}
81
+
82
+ Knowledge Base Usage:
83
+ - With context: {stats['knowledge_base_usage'].get('with_context', 0)}
84
+ - Without context: {stats['knowledge_base_usage'].get('without_context', 0)}
85
+
86
+ Usage Patterns:
87
+ - Daily Activity: {temporal['daily_activity']}
88
+ - Hourly Distribution: {temporal['hourly_pattern']}
89
+ """
90
+ return report
api/main.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from analysis import LogAnalyzer
3
+
4
+ router = APIRouter()
5
+
6
+ @router.get("/analysis/basic")
7
+ async def get_basic_analysis():
8
+ analyzer = LogAnalyzer()
9
+ return analyzer.get_basic_stats()
10
+
11
+ @router.get("/analysis/temporal")
12
+ async def get_temporal_analysis():
13
+ analyzer = LogAnalyzer()
14
+ return analyzer.temporal_analysis()
15
+
16
+ @router.get("/analysis/report")
17
+ async def get_full_report():
18
+ analyzer = LogAnalyzer()
19
+ return {"report": analyzer.generate_report()}
app - Copy.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 langchain_core.runnables import RunnableLambda
13
+ import requests
14
+ import json
15
+
16
+ # Логирует взаимодействие в JSON-файл
17
+ from datetime import datetime
18
+
19
+
20
+ def log_interaction(user_input: str, bot_response: str):
21
+ """Логирует взаимодействие в JSON-файл"""
22
+ log_entry = {
23
+ "timestamp": datetime.now().isoformat(),
24
+ "user_input": user_input,
25
+ "bot_response": bot_response
26
+ }
27
+
28
+ log_dir = "chat_history"
29
+ os.makedirs(log_dir, exist_ok=True)
30
+
31
+ log_path = os.path.join(log_dir, "chat_logs.json")
32
+ with open(log_path, "a") as f:
33
+ f.write(json.dumps(log_entry) + "\n")
34
+
35
+ #
36
+
37
+
38
+
39
+ # Page configuration
40
+ st.set_page_config(page_title="Status Law Assistant", page_icon="⚖️")
41
+
42
+ # Knowledge base info in session_state
43
+ if 'kb_info' not in st.session_state:
44
+ st.session_state.kb_info = {
45
+ 'build_time': None,
46
+ 'size': None
47
+ }
48
+
49
+ # Display title and knowledge base info
50
+ # st.title("www.Status.Law Legal Assistant")
51
+
52
+ st.markdown(
53
+ '''
54
+ <h1>
55
+ ⚖️
56
+ <a href="https://status.law/" style="text-decoration: underline; color: blue; font-size: inherit;">
57
+ Status.Law
58
+ </a>
59
+ Legal Assistant
60
+ </h1>
61
+ ''',
62
+ unsafe_allow_html=True
63
+ )
64
+
65
+ if st.session_state.kb_info['build_time'] and st.session_state.kb_info['size']:
66
+ st.caption(f"(Knowledge base build time: {st.session_state.kb_info['build_time']:.2f} seconds, "
67
+ f"size: {st.session_state.kb_info['size']:.2f} MB)")
68
+
69
+ # Path to store vector database
70
+ VECTOR_STORE_PATH = "vector_store"
71
+
72
+ # Создание папки истории, если она не существует
73
+ if not os.path.exists("chat_history"):
74
+ os.makedirs("chat_history")
75
+
76
+ # Website URLs
77
+ urls = [
78
+ "https://status.law",
79
+ "https://status.law/about",
80
+ "https://status.law/careers",
81
+ "https://status.law/tariffs-for-services-of-protection-against-extradition",
82
+ "https://status.law/challenging-sanctions",
83
+ "https://status.law/law-firm-contact-legal-protection"
84
+ "https://status.law/cross-border-banking-legal-issues",
85
+ "https://status.law/extradition-defense",
86
+ "https://status.law/international-prosecution-protection",
87
+ "https://status.law/interpol-red-notice-removal",
88
+ "https://status.law/practice-areas",
89
+ "https://status.law/reputation-protection",
90
+ "https://status.law/faq"
91
+ ]
92
+
93
+ # Load secrets
94
+ try:
95
+ GROQ_API_KEY = st.secrets["GROQ_API_KEY"]
96
+ except Exception as e:
97
+ st.error("Error loading secrets. Please check your configuration.")
98
+ st.stop()
99
+
100
+ # Initialize models
101
+ @st.cache_resource
102
+ def init_models():
103
+ llm = ChatGroq(
104
+ model_name="llama-3.3-70b-versatile",
105
+ temperature=0.6,
106
+ api_key=GROQ_API_KEY
107
+ )
108
+ embeddings = HuggingFaceEmbeddings(
109
+ model_name="intfloat/multilingual-e5-large-instruct"
110
+ )
111
+ return llm, embeddings
112
+
113
+ # Build knowledge base
114
+ def build_knowledge_base(embeddings):
115
+ start_time = time.time()
116
+
117
+ documents = []
118
+ with st.status("Loading website content...") as status:
119
+ for url in urls:
120
+ try:
121
+ loader = WebBaseLoader(url)
122
+ docs = loader.load()
123
+ documents.extend(docs)
124
+ status.update(label=f"Loaded {url}")
125
+ except Exception as e:
126
+ st.error(f"Error loading {url}: {str(e)}")
127
+
128
+ text_splitter = RecursiveCharacterTextSplitter(
129
+ chunk_size=500,
130
+ chunk_overlap=100
131
+ )
132
+ chunks = text_splitter.split_documents(documents)
133
+
134
+ vector_store = FAISS.from_documents(chunks, embeddings)
135
+ vector_store.save_local(VECTOR_STORE_PATH)
136
+
137
+ end_time = time.time()
138
+ build_time = end_time - start_time
139
+
140
+ # Calculate knowledge base size
141
+ total_size = 0
142
+ for path, dirs, files in os.walk(VECTOR_STORE_PATH):
143
+ for f in files:
144
+ fp = os.path.join(path, f)
145
+ total_size += os.path.getsize(fp)
146
+ size_mb = total_size / (1024 * 1024)
147
+
148
+ # Save knowledge base info
149
+ st.session_state.kb_info['build_time'] = build_time
150
+ st.session_state.kb_info['size'] = size_mb
151
+
152
+ st.success(f"""
153
+ Knowledge base created successfully:
154
+ - Time taken: {build_time:.2f} seconds
155
+ - Size: {size_mb:.2f} MB
156
+ - Number of chunks: {len(chunks)}
157
+ """)
158
+
159
+ return vector_store
160
+
161
+ # Main function
162
+ def main():
163
+ # Initialize models
164
+ llm, embeddings = init_models()
165
+
166
+ # Check if knowledge base exists
167
+ if not os.path.exists(VECTOR_STORE_PATH):
168
+ st.warning("Knowledge base not found.")
169
+ if st.button("Create Knowledge Base"):
170
+ vector_store = build_knowledge_base(embeddings)
171
+ st.session_state.vector_store = vector_store
172
+ st.rerun()
173
+ else:
174
+ if 'vector_store' not in st.session_state:
175
+ st.session_state.vector_store = FAISS.load_local(
176
+ VECTOR_STORE_PATH,
177
+ embeddings,
178
+ allow_dangerous_deserialization=True
179
+ )
180
+
181
+ # Chat mode
182
+ if 'vector_store' in st.session_state:
183
+ if 'messages' not in st.session_state:
184
+ st.session_state.messages = []
185
+
186
+ # Display chat history
187
+ for message in st.session_state.messages:
188
+ st.chat_message("user").write(message["question"])
189
+ st.chat_message("assistant").write(message["answer"])
190
+
191
+ # User input
192
+ if question := st.chat_input("Ask your question"):
193
+ st.chat_message("user").write(question)
194
+
195
+ # Retrieve context and generate response
196
+ with st.chat_message("assistant"):
197
+ with st.spinner("Thinking..."):
198
+ context = st.session_state.vector_store.similarity_search(question)
199
+ context_text = "\n".join([doc.page_content for doc in context])
200
+
201
+ prompt = PromptTemplate.from_template("""
202
+ You are a helpful and polite legal assistant at Status Law.
203
+ You answer in the language in which the question was asked.
204
+ Answer the question based on the context provided.
205
+ If you cannot answer based on the context, say so politely and offer to contact Status Law directly via the following channels:
206
+ - For all users: +32465594521 (landline phone).
207
+ - For English and Swedish speakers only: +46728495129 (available on WhatsApp, Telegram, Signal, IMO).
208
+ - Provide a link to the contact form: [Contact Form](https://status.law/law-firm-contact-legal-protection/).
209
+ 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.
210
+
211
+ 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.
212
+
213
+ Also, offer free consultations if they are available and suitable for the user's request.
214
+ Answer professionally but in a friendly manner.
215
+
216
+ Example:
217
+ Q: How can I challenge the sanctions?
218
+ 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/).
219
+
220
+ Context: {context}
221
+ Question: {question}
222
+ """)
223
+
224
+ chain = prompt | llm | StrOutputParser()
225
+ response = chain.invoke({
226
+ "context": context_text,
227
+ "question": question
228
+ })
229
+
230
+ st.write(response)
231
+
232
+
233
+ # В блоке генерации ответа (после st.write(response))
234
+ log_interaction(question, response)
235
+ # Save chat history
236
+ st.session_state.messages.append({
237
+ "question": question,
238
+ "answer": response
239
+ })
240
+
241
+ if __name__ == "__main__":
242
+ main()
app.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
gitattributes ADDED
@@ -0,0 +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
+
37
+
38
+ * text=auto eol=crlf
39
+
40
+ *.bin binary
41
+
42
+ .gitignore text eol=lf
43
+ .gitattributes text eol=lf
44
+
gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ *.env
2
+
3
+ venv
4
+ .streamlit/secrets.toml
requirements.txt ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit
2
+ langchain-community
3
+ langchain-core
4
+ langchain-huggingface
5
+ langchain-groq
6
+ python-dotenv
7
+ beautifulsoup4
8
+ faiss-cpu
9
+ requests
10
+ langgraph
11
+ langchain-anthropic
12
+ fastapi
13
+ uvicorn[standard]
14
+ pydantic
15
+ python-multipart
16
+ pandas
17
+ langchain
18
+
19
+
20
+
21
+
run.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Запуск Streamlit и FastAPI параллельно
4
+ streamlit run app.py & # Запуск чат-бота
5
+ uvicorn api.main:app --reload # Запуск API для анализа логов