cryogenic22 commited on
Commit
3bf7db5
·
verified ·
1 Parent(s): 90451e9

Create utils/legal_notebook_interface.py

Browse files
Files changed (1) hide show
  1. utils/legal_notebook_interface.py +242 -0
utils/legal_notebook_interface.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from typing import List, Dict
3
+ 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
10
+
11
+ # Initialize session state
12
+ if "active_documents" not in st.session_state:
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;
48
+ margin: 10px 0;
49
+ border-radius: 8px;
50
+ }
51
+ .user-message {
52
+ background-color: #f0f7ff;
53
+ border-left: 4px solid #1976d2;
54
+ }
55
+ .assistant-message {
56
+ background-color: #f8f9fa;
57
+ border-left: 4px solid #4caf50;
58
+ }
59
+ .suggestion-chip {
60
+ display: inline-block;
61
+ padding: 5px 15px;
62
+ margin: 5px;
63
+ background-color: #e3f2fd;
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
+
77
+ # Create two-column layout
78
+ col1, col2 = st.columns([2, 3])
79
+
80
+ # Document Panel (Left)
81
+ with col1:
82
+ self._render_document_panel()
83
+
84
+ # Chat Panel (Right)
85
+ with col2:
86
+ self._render_chat_panel()
87
+
88
+ def _render_document_panel(self):
89
+ """Render the document viewing and management panel."""
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
+ ]