cryogenic22 commited on
Commit
a3bfa6a
·
verified ·
1 Parent(s): 53dcfb5

Update utils/legal_notebook_interface.py

Browse files
Files changed (1) hide show
  1. utils/legal_notebook_interface.py +105 -156
utils/legal_notebook_interface.py CHANGED
@@ -4,6 +4,7 @@ import datetime
4
 
5
  class LegalNotebookInterface:
6
  def __init__(self, case_manager, vector_store, document_processor):
 
7
  self.case_manager = case_manager
8
  self.vector_store = vector_store
9
  self.document_processor = document_processor
@@ -13,35 +14,19 @@ class LegalNotebookInterface:
13
  st.session_state.active_documents = []
14
  if "chat_history" not in st.session_state:
15
  st.session_state.chat_history = []
16
- if "document_context" not in st.session_state:
17
- st.session_state.document_context = None
18
- if "suggestions" not in st.session_state:
19
- st.session_state.suggestions = []
20
 
21
  def render(self):
22
  """Render the main notebook interface."""
23
- # Custom CSS for NotebookLM-like interface
24
  st.markdown("""
25
  <style>
26
- .main-container {
27
- max-width: 1200px;
28
- margin: auto;
29
- }
30
  .document-panel {
31
  background-color: #f8f9fa;
32
  border-radius: 10px;
33
  padding: 20px;
34
  margin: 10px;
35
- height: calc(100vh - 100px);
36
- overflow-y: auto;
37
- }
38
- .chat-panel {
39
- background-color: white;
40
- border-radius: 10px;
41
- padding: 20px;
42
- margin: 10px;
43
- height: calc(100vh - 100px);
44
- overflow-y: auto;
45
  }
46
  .message {
47
  padding: 15px;
@@ -64,13 +49,6 @@ class LegalNotebookInterface:
64
  border-radius: 20px;
65
  cursor: pointer;
66
  }
67
- .document-snippet {
68
- padding: 10px;
69
- background-color: #fff;
70
- border-left: 3px solid #ffd700;
71
- margin: 10px 0;
72
- border-radius: 4px;
73
- }
74
  </style>
75
  """, unsafe_allow_html=True)
76
 
@@ -90,153 +68,124 @@ class LegalNotebookInterface:
90
  st.markdown("### 📚 Documents")
91
 
92
  # Document selection
93
- all_cases = self.case_manager.get_all_cases()
94
- if all_cases:
95
- selected_case = st.selectbox(
96
- "Select Case",
97
- all_cases,
98
- format_func=lambda x: x['title']
99
- )
 
 
 
 
 
 
 
100
 
101
- if selected_case:
102
- documents = self.case_manager.list_documents(selected_case['id'])
103
- selected_docs = st.multiselect(
104
- "Select Documents to Analyze",
105
- documents,
106
- format_func=lambda x: x['title']
107
- )
108
-
109
- if selected_docs:
110
- st.session_state.active_documents = selected_docs
111
-
112
- # Show document previews
113
- for doc in selected_docs:
114
- with st.expander(f"📄 {doc['title']}", expanded=False):
115
- st.markdown("#### Quick Preview")
116
- content = doc.get('content', '')[:500]
117
- st.markdown(f"{content}...")
118
-
119
- # Document metadata
120
- st.markdown("#### Metadata")
121
- st.json({
122
- 'Type': doc.get('metadata', {}).get('type', 'Unknown'),
123
- 'Added': doc.get('added_at', 'Unknown'),
124
- 'Pages': doc.get('metadata', {}).get('page_count', 'Unknown')
125
- })
126
 
127
  def _render_chat_panel(self):
128
- """Render the chat and analysis panel."""
129
- st.markdown("### 💬 Legal Analysis")
130
 
 
 
 
 
131
  # Display chat history
132
  for message in st.session_state.chat_history:
133
- self._render_message(message)
134
-
135
- # Suggestions
136
- if st.session_state.suggestions:
137
- st.markdown("#### 💡 Suggested Questions")
138
- cols = st.columns(2)
139
- for idx, suggestion in enumerate(st.session_state.suggestions):
140
- with cols[idx % 2]:
141
- if st.button(suggestion, key=f"suggestion_{idx}"):
142
- self._handle_input(suggestion)
143
 
144
  # Chat input
145
- with st.container():
146
- chat_input = st.text_area("Ask about your documents...", height=100)
147
- col1, col2 = st.columns([1, 5])
148
- with col1:
149
- if st.button("Send", type="primary"):
150
- if chat_input:
151
- self._handle_input(chat_input)
152
- with col2:
153
- st.markdown("*Press Enter to send*")
154
-
155
- def _render_message(self, message: Dict):
156
- """Render a single message with citations and context."""
157
- message_class = "user-message" if message['role'] == 'user' else 'assistant-message'
158
-
159
- st.markdown(f"""
160
- <div class="message {message_class}">
161
- <p>{message['content']}</p>
162
- {self._render_citations(message.get('citations', [])) if message.get('citations') else ''}
163
- </div>
164
- """, unsafe_allow_html=True)
165
 
166
- def _render_citations(self, citations: List[Dict]) -> str:
167
- """Render document citations and snippets."""
168
- if not citations:
169
- return ""
170
-
171
- citations_html = "<div class='citations'>"
172
- for citation in citations:
173
- citations_html += f"""
174
- <div class="document-snippet">
175
- <small>From {citation['document']}</small>
176
- <p>{citation['text']}</p>
177
- </div>
178
- """
179
- citations_html += "</div>"
180
- return citations_html
181
-
182
- def _handle_input(self, input_text: str):
183
  """Process user input and generate response."""
 
 
 
 
184
  # Add user message
185
  st.session_state.chat_history.append({
186
- 'role': 'user',
187
- 'content': input_text,
188
- 'timestamp': datetime.datetime.now().isoformat()
189
  })
190
 
191
- # Get relevant context from documents
192
- context_chunks = []
193
- for doc in st.session_state.active_documents:
194
- chunks = self.vector_store.similarity_search(
195
- input_text,
196
- filter_criteria={"doc_id": doc['id']},
197
- k=2
198
- )
199
- context_chunks.extend(chunks)
200
-
201
- # Generate response with citations
202
- response = {
203
- 'role': 'assistant',
204
- 'content': self._generate_response(input_text, context_chunks),
205
- 'citations': [
206
- {
207
- 'document': chunk['metadata']['title'],
208
- 'text': chunk['text']
209
- }
210
- for chunk in context_chunks[:2]
211
- ],
212
- 'timestamp': datetime.datetime.now().isoformat()
213
- }
214
 
215
- # Add assistant message
216
- st.session_state.chat_history.append(response)
 
 
 
 
217
 
218
- # Generate new suggestions
219
- self._generate_suggestions(input_text, context_chunks)
 
 
 
 
 
 
 
 
220
 
221
- def _generate_response(self, query: str, context_chunks: List[Dict]) -> str:
222
- """Generate response using the legal analysis pipeline."""
223
  # Combine context from chunks
224
- context = "\n\n".join([chunk['text'] for chunk in context_chunks])
225
 
226
- # Get response from your existing chat interface
227
- response_content = f"Analysis based on {len(context_chunks)} relevant document sections:\n\n"
228
- response_content += "1. Key findings...\n"
229
- response_content += "2. Legal implications...\n"
230
- response_content += "3. Recommendations...\n"
231
 
232
- return response_content
233
-
234
- def _generate_suggestions(self, query: str, context_chunks: List[Dict]):
235
- """Generate follow-up question suggestions."""
236
- # Generate relevant follow-up questions based on context
237
- st.session_state.suggestions = [
238
- "Could you elaborate on the legal implications?",
239
- "What are the relevant precedents?",
240
- "Are there any potential risks?",
241
- "How does this compare to similar cases?"
242
- ]
 
 
 
 
 
 
 
4
 
5
  class LegalNotebookInterface:
6
  def __init__(self, case_manager, vector_store, document_processor):
7
+ """Initialize the notebook interface with required components."""
8
  self.case_manager = case_manager
9
  self.vector_store = vector_store
10
  self.document_processor = document_processor
 
14
  st.session_state.active_documents = []
15
  if "chat_history" not in st.session_state:
16
  st.session_state.chat_history = []
17
+ if "current_case" not in st.session_state:
18
+ st.session_state.current_case = None
 
 
19
 
20
  def render(self):
21
  """Render the main notebook interface."""
22
+ # Add custom styling
23
  st.markdown("""
24
  <style>
 
 
 
 
25
  .document-panel {
26
  background-color: #f8f9fa;
27
  border-radius: 10px;
28
  padding: 20px;
29
  margin: 10px;
 
 
 
 
 
 
 
 
 
 
30
  }
31
  .message {
32
  padding: 15px;
 
49
  border-radius: 20px;
50
  cursor: pointer;
51
  }
 
 
 
 
 
 
 
52
  </style>
53
  """, unsafe_allow_html=True)
54
 
 
68
  st.markdown("### 📚 Documents")
69
 
70
  # Document selection
71
+ cases = self.case_manager.get_all_cases()
72
+ if not cases:
73
+ st.info("No cases found. Please create a case and add documents first.")
74
+ return
75
+
76
+ selected_case = st.selectbox(
77
+ "Select Case",
78
+ cases,
79
+ format_func=lambda x: x['title']
80
+ )
81
+
82
+ if selected_case:
83
+ st.session_state.current_case = selected_case['id']
84
+ documents = self.case_manager.list_documents(selected_case['id'])
85
 
86
+ if documents:
87
+ st.write("#### Available Documents")
88
+ for doc in documents:
89
+ with st.expander(f"📄 {doc['title']}", expanded=False):
90
+ st.write("**Added:** ", doc.get('added_at', 'Unknown'))
91
+ st.write("**Type:** ", doc.get('metadata', {}).get('document_type', 'Unknown'))
92
+ if st.button("View Details", key=f"view_{doc['id']}"):
93
+ self._show_document_details(doc)
94
+ else:
95
+ st.info("No documents in this case. Please add documents first.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  def _render_chat_panel(self):
98
+ """Render the chat and analysis interface."""
99
+ st.markdown("### 💬 Document Analysis")
100
 
101
+ if not st.session_state.current_case:
102
+ st.info("Please select a case from the left panel to start analysis.")
103
+ return
104
+
105
  # Display chat history
106
  for message in st.session_state.chat_history:
107
+ message_class = "user-message" if message["role"] == "user" else "assistant-message"
108
+ st.markdown(f"""
109
+ <div class="message {message_class}">
110
+ {message["content"]}
111
+ </div>
112
+ """, unsafe_allow_html=True)
 
 
 
 
113
 
114
  # Chat input
115
+ if prompt := st.chat_input("Ask about your documents..."):
116
+ self._handle_chat_input(prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
+ def _handle_chat_input(self, prompt: str):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  """Process user input and generate response."""
120
+ if not st.session_state.current_case:
121
+ st.error("Please select a case first.")
122
+ return
123
+
124
  # Add user message
125
  st.session_state.chat_history.append({
126
+ "role": "user",
127
+ "content": prompt,
128
+ "timestamp": datetime.datetime.now().isoformat()
129
  })
130
 
131
+ # Get documents from current case
132
+ documents = self.case_manager.list_documents(st.session_state.current_case)
133
+ if not documents:
134
+ st.error("No documents available for analysis.")
135
+ return
136
+
137
+ try:
138
+ # Get relevant chunks from documents
139
+ chunks = []
140
+ for doc in documents:
141
+ doc_chunks = self.vector_store.similarity_search(
142
+ prompt,
143
+ filter_criteria={"doc_id": doc['id']},
144
+ k=2
145
+ )
146
+ if doc_chunks:
147
+ chunks.extend(doc_chunks)
 
 
 
 
 
 
148
 
149
+ # Generate response
150
+ response = {
151
+ "role": "assistant",
152
+ "content": self._generate_response(prompt, chunks),
153
+ "timestamp": datetime.datetime.now().isoformat()
154
+ }
155
 
156
+ # Add response to chat history
157
+ st.session_state.chat_history.append(response)
158
+
159
+ except Exception as e:
160
+ st.error(f"Error analyzing documents: {str(e)}")
161
+
162
+ def _generate_response(self, prompt: str, chunks: List[Dict]) -> str:
163
+ """Generate response based on document chunks."""
164
+ if not chunks:
165
+ return "I couldn't find any relevant information in the documents. Please try rephrasing your question."
166
 
 
 
167
  # Combine context from chunks
168
+ context = "\n\n".join([chunk['text'] for chunk in chunks])
169
 
170
+ # Generate a simple response (replace with your actual response generation)
171
+ response = f"Based on the documents, I found {len(chunks)} relevant sections:\n\n"
172
+ for i, chunk in enumerate(chunks, 1):
173
+ response += f"{i}. {chunk['text'][:200]}...\n\n"
 
174
 
175
+ return response
176
+
177
+ def _show_document_details(self, doc: Dict):
178
+ """Show detailed document information."""
179
+ st.markdown("#### Document Details")
180
+ st.write("**Title:** ", doc['title'])
181
+ st.write("**Added:** ", doc.get('added_at', 'Unknown'))
182
+
183
+ metadata = doc.get('metadata', {})
184
+ if metadata:
185
+ st.write("**Document Type:** ", metadata.get('document_type', 'Unknown'))
186
+ st.write("**Word Count:** ", metadata.get('word_count', 'Unknown'))
187
+
188
+ if 'entities' in metadata:
189
+ st.write("**Named Entities:** ")
190
+ for entity_type, entities in metadata['entities'].items():
191
+ st.write(f"- {entity_type}: {', '.join(entities[:5])}")