Amodit commited on
Commit
7b78b6f
·
1 Parent(s): 1179ef6

Refactor frontend to use Backend API

Browse files
Files changed (2) hide show
  1. main_streamlit.py +228 -5
  2. requirements.txt +2 -0
main_streamlit.py CHANGED
@@ -2,13 +2,236 @@
2
 
3
  import os
4
  import streamlit as st
 
5
  from dotenv import load_dotenv
6
 
7
- # --- Agent and Component Imports ---
8
- from agents.demystifier_agent import process_document_for_demystification
9
- from components.video_recorder import record_consent_video
10
- from utils.pdf_generator import generate_formatted_pdf
11
- from components.chat_interface import chat_interface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
 
14
  # --- 1. Initial Setup ---
 
2
 
3
  import os
4
  import streamlit as st
5
+ import requests
6
  from dotenv import load_dotenv
7
 
8
+ # --- 1. Initial Setup ---
9
+ load_dotenv()
10
+ st.set_page_config(layout="wide", page_title="Jan-Contract Unified Assistant", page_icon="⚖️")
11
+
12
+ # Backend Configuration
13
+ # In production (Streamlit Cloud), set BACKEND_URL in secrets or env vars
14
+ BACKEND_URL = os.getenv("BACKEND_URL", "http://127.0.0.1:8000")
15
+
16
+ # Only strip trailing slash if it exists, to avoid removing the last char of a valid URL if logic differs
17
+ if BACKEND_URL.endswith("/"):
18
+ BACKEND_URL = BACKEND_URL[:-1]
19
+
20
+ # --- Custom CSS ---
21
+ st.markdown("""
22
+ <style>
23
+ .main-header { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #333; }
24
+ h1 { color: #1A73E8; }
25
+ h2, h3 { color: #424242; }
26
+ .stButton>button { color: #ffffff; background-color: #1A73E8; border-radius: 5px; }
27
+ .success-msg { color: #2e7d32; font-weight: bold; }
28
+ .error-msg { color: #c62828; font-weight: bold; }
29
+ </style>
30
+ """, unsafe_allow_html=True)
31
+
32
+ st.title("Jan-Contract: Digital Workforce Assistant")
33
+ st.caption(f"Connected to Backend: `{BACKEND_URL}`")
34
+ st.write("Empowering India's workforce with accessible legal tools and government scheme discovery.")
35
+
36
+ # --- 2. Streamlit UI with Tabs ---
37
+ tab1, tab2, tab3 = st.tabs([
38
+ "Contract Generator",
39
+ "Scheme Finder",
40
+ "Document Demystifier"
41
+ ])
42
+
43
+ # --- TAB 1: Contract Generator ---
44
+ with tab1:
45
+ st.header("Digital Agreement Generator")
46
+ st.write("Create a clear digital agreement from plain text and record video consent.")
47
+
48
+ col1, col2 = st.columns([1, 1])
49
+
50
+ with col1:
51
+ st.subheader("Agreement Details")
52
+ user_request = st.text_area("Describe the terms of the agreement...", height=150, key="contract_request", placeholder="E.g., I, Rajesh, agree to paint Mr. Sharma's house for 5000 rupees by next Tuesday.")
53
+
54
+ if st.button("Generate Agreement", type="primary", key="btn_generate_contract"):
55
+ if user_request:
56
+ with st.spinner("Drafting agreement via API..."):
57
+ try:
58
+ payload = {"user_request": user_request}
59
+ response = requests.post(f"{BACKEND_URL}/api/v1/contracts/generate", json=payload)
60
+
61
+ if response.status_code == 200:
62
+ data = response.json()
63
+ if data.get("success"):
64
+ st.session_state.legal_result = data["data"]
65
+ if 'video_path_from_component' in st.session_state:
66
+ del st.session_state['video_path_from_component']
67
+ else:
68
+ st.error(f"API Error: {data.get('message')}")
69
+ else:
70
+ st.error(f"Server Error: {response.text}")
71
+ except Exception as e:
72
+ st.error(f"Connection failed: {e}")
73
+ else:
74
+ st.warning("Please describe the agreement details.")
75
+
76
+ with col2:
77
+ if 'legal_result' in st.session_state:
78
+ result = st.session_state.legal_result
79
+ contract_text = result.get('contract', '')
80
+
81
+ st.subheader("Drafted Agreement")
82
+ with st.container(border=True):
83
+ st.markdown(contract_text)
84
+
85
+ # PDF Download via API
86
+ if st.button("Download PDF"):
87
+ try:
88
+ pdf_Payload = {"user_request": result.get('user_request', user_request)}
89
+ pdf_resp = requests.post(f"{BACKEND_URL}/api/v1/contracts/generate-pdf", json=pdf_Payload)
90
+ if pdf_resp.status_code == 200:
91
+ st.download_button(label="Click to Save PDF", data=pdf_resp.content, file_name="agreement.pdf", mime="application/pdf")
92
+ else:
93
+ st.error("Failed to generate PDF")
94
+ except Exception as e:
95
+ st.error(f"Download failed: {e}")
96
+
97
+ if result.get('legal_trivia') and result['legal_trivia'].get('trivia'):
98
+ with st.expander("Legal Insights"):
99
+ for item in result['legal_trivia']['trivia']:
100
+ st.markdown(f"**{item['point']}**")
101
+ st.caption(item['explanation'])
102
+ st.markdown(f"[Source]({item['source_url']})")
103
+
104
+ st.divider()
105
+ from components.video_recorder import record_consent_video
106
+ st.subheader("Video Consent Recording")
107
+ saved_video_path = record_consent_video()
108
+
109
+ # Upload video to backend if recorded
110
+ if saved_video_path and 'legal_result' in st.session_state:
111
+ contract_id = st.session_state.legal_result.get('contract_id')
112
+ if contract_id:
113
+ if st.button("Upload Consent to Server"):
114
+ try:
115
+ with open(saved_video_path, 'rb') as f:
116
+ files = {'file': (os.path.basename(saved_video_path), f, 'video/mp4')}
117
+ data = {'contract_id': contract_id, 'consent_text': "I agree to the terms."}
118
+ up_resp = requests.post(f"{BACKEND_URL}/api/v1/media/upload-video", files=files, data=data)
119
+ if up_resp.status_code == 200:
120
+ st.success("Consent uploaded to server securely!")
121
+ else:
122
+ st.error(f"Upload failed: {up_resp.text}")
123
+ except Exception as e:
124
+ st.error(f"Upload error: {e}")
125
+
126
+ # --- TAB 2: Scheme Finder ---
127
+ with tab2:
128
+ st.header("Government Scheme Finder")
129
+ st.write("Find relevant government schemes based on your profile.")
130
+
131
+ user_profile = st.text_input("Enter your profile description...", key="scheme_profile", placeholder="E.g., A female farmer in Maharashtra owning 2 acres of land.")
132
+
133
+ if st.button("Search Schemes", type="primary", key="btn_find_schemes"):
134
+ if user_profile:
135
+ with st.spinner("Searching schemes via API..."):
136
+ try:
137
+ payload = {"user_profile": user_profile}
138
+ response = requests.post(f"{BACKEND_URL}/api/v1/schemes/find", json=payload)
139
+
140
+ if response.status_code == 200:
141
+ st.session_state.scheme_response = response.json().get('data', {})
142
+ else:
143
+ st.error(f"Error: {response.text}")
144
+ except Exception as e:
145
+ st.error(f"Connection error: {e}")
146
+ else:
147
+ st.warning("Please enter a profile description.")
148
+
149
+ if 'scheme_response' in st.session_state:
150
+ response = st.session_state.scheme_response
151
+ st.subheader(f"Results")
152
+ schemes = response.get('schemes', [])
153
+ if schemes:
154
+ for scheme in schemes:
155
+ with st.container(border=True):
156
+ st.markdown(f"#### {scheme.get('scheme_name')}")
157
+ st.write(scheme.get('description'))
158
+ st.write(f"**Target Audience:** {scheme.get('target_audience')}")
159
+ st.markdown(f"[Official Website]({scheme.get('official_link')})")
160
+ else:
161
+ st.info("No specific schemes found.")
162
+
163
+ # --- TAB 3: Demystifier ---
164
+ with tab3:
165
+ st.header("Document Demystifier")
166
+ st.write("Upload a legal document to get a simplified summary and ask questions.")
167
+
168
+ uploaded_file = st.file_uploader("Upload PDF Document", type="pdf", key="demystify_uploader")
169
+
170
+ if uploaded_file and st.button("Analyze Document", type="primary"):
171
+ with st.spinner("Uploading and analyzing..."):
172
+ try:
173
+ files = {"file": (uploaded_file.name, uploaded_file.getvalue(), "application/pdf")}
174
+ response = requests.post(f"{BACKEND_URL}/api/v1/demystify/upload", files=files)
175
+
176
+ if response.status_code == 200:
177
+ st.session_state.demystify_data = response.json().get('data', {})
178
+ st.session_state.session_id = st.session_state.demystify_data.get('session_id')
179
+ st.success("Analysis complete!")
180
+ else:
181
+ st.error(f"Analysis failed: {response.text}")
182
+ except Exception as e:
183
+ st.error(f"Connection error: {e}")
184
+
185
+ if 'demystify_data' in st.session_state:
186
+ st.divider()
187
+ report = st.session_state.demystify_data.get('report', {})
188
+
189
+ tab_summary, tab_chat = st.tabs(["Summary & Analysis", "Chat with Document"])
190
+
191
+ with tab_summary:
192
+ st.subheader("Document Summary")
193
+ st.write(report.get('summary', ''))
194
+
195
+ st.subheader("Key Terms Explained")
196
+ for term in report.get('key_terms', []):
197
+ with st.expander(f"{term.get('term')}"):
198
+ st.write(term.get('explanation'))
199
+ st.markdown(f"[Learn More]({term.get('resource_link')})")
200
+
201
+ st.info(f"**Advice:** {report.get('overall_advice')}")
202
+
203
+ with tab_chat:
204
+ st.subheader("Ask Questions")
205
+
206
+ # Simple Chat Interface for API
207
+ if "messages" not in st.session_state:
208
+ st.session_state.messages = []
209
+
210
+ for message in st.session_state.messages:
211
+ with st.chat_message(message["role"]):
212
+ st.markdown(message["content"])
213
+
214
+ if prompt := st.chat_input("Ask about the document..."):
215
+ st.session_state.messages.append({"role": "user", "content": prompt})
216
+ with st.chat_message("user"):
217
+ st.markdown(prompt)
218
+
219
+ with st.chat_message("assistant"):
220
+ with st.spinner("Thinking..."):
221
+ try:
222
+ payload = {
223
+ "session_id": st.session_state.session_id,
224
+ "question": prompt
225
+ }
226
+ chat_resp = requests.post(f"{BACKEND_URL}/api/v1/demystify/chat", json=payload)
227
+ if chat_resp.status_code == 200:
228
+ answer = chat_resp.json()['data']['answer']
229
+ st.markdown(answer)
230
+ st.session_state.messages.append({"role": "assistant", "content": answer})
231
+ else:
232
+ st.error("Failed to get answer.")
233
+ except Exception as e:
234
+ st.error(f"Error: {e}")
235
 
236
 
237
  # --- 1. Initial Setup ---
requirements.txt CHANGED
@@ -21,6 +21,8 @@ python-multipart>=0.0.6
21
  # Web Frameworks
22
  fastapi>=0.104.0
23
  uvicorn>=0.24.0
 
 
24
 
25
  # Utilities
26
  python-dotenv>=1.0.0
 
21
  # Web Frameworks
22
  fastapi>=0.104.0
23
  uvicorn>=0.24.0
24
+ requests>=2.31.0
25
+ streamlit>=1.28.0
26
 
27
  # Utilities
28
  python-dotenv>=1.0.0