Files changed (1) hide show
  1. frontend.py +551 -0
frontend.py ADDED
@@ -0,0 +1,551 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+
4
+ API_URL = "http://localhost:7860" # Change to your backend URL
5
+
6
+ st.title("Financial Statements Frontend")
7
+
8
+ main_section = st.sidebar.radio(
9
+ "Section",
10
+ ["Financial Statement Generation", "RLHF Management"]
11
+ )
12
+
13
+ if main_section == "Financial Statement Generation":
14
+ endpoint = st.sidebar.selectbox(
15
+ "Choose Statement Endpoint",
16
+ ["Balance Sheet", "Profit & Loss", "Cash Flow", "Notes", "Interactive Notes"]
17
+ )
18
+
19
+ if endpoint == "Interactive Notes":
20
+ st.header("🎯 Interactive Notes Generation with Feedback")
21
+
22
+ # Session Management
23
+ col1, col2 = st.columns([3, 1])
24
+ with col1:
25
+ default_session_id = st.session_state.get('session_id', '')
26
+ session_id = st.text_input("Session ID (leave empty for new session)",
27
+ value=default_session_id,
28
+ placeholder="Auto-generated for new sessions")
29
+ with col2:
30
+ if st.button("πŸ” Check Session Status"):
31
+ if session_id:
32
+ try:
33
+ resp = requests.get(f"{API_URL}/notes-llm/session/{session_id}")
34
+ if resp.status_code == 200:
35
+ session_data = resp.json()
36
+ st.success(f"Session Status: {session_data['status']}")
37
+ st.info(f"Iterations: {session_data['current_iteration']}")
38
+ st.info(f"Feedbacks: {len(session_data['feedback_history'])}")
39
+ else:
40
+ st.error("Session not found")
41
+ except Exception as e:
42
+ st.error(f"Error checking session: {e}")
43
+
44
+ # File Upload
45
+ st.subheader("πŸ“ Upload Trial Balance")
46
+ f = st.file_uploader("Upload Excel file", type=["xlsx"])
47
+
48
+ # Workflow Tabs
49
+ tab1, tab2, tab3, tab4 = st.tabs(["πŸš€ Initial Generation", "πŸ’¬ Submit Feedback",
50
+ "πŸ”„ Generate Improved", "βœ… Final Approval"])
51
+
52
+ with tab1:
53
+ st.subheader("Initial Notes Generation")
54
+ use_rlhf = st.checkbox("Use RLHF (if available)", value=False)
55
+
56
+ if 'initial_notes_generated' in st.session_state and st.session_state['initial_notes_generated']:
57
+ st.success("βœ… Initial notes have been generated!")
58
+ st.info(f"πŸ“‹ Session ID: {st.session_state['session_id']}")
59
+
60
+ st.download_button(
61
+ "πŸ“₯ Download Initial Notes",
62
+ data=st.session_state['notes_content'],
63
+ file_name=st.session_state['notes_filename'],
64
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
65
+ )
66
+
67
+ st.subheader("πŸ“Š Generation Info")
68
+ col1, col2, col3 = st.columns(3)
69
+ with col1:
70
+ st.metric("Validation Score", st.session_state.get('validation_score', 'N/A'))
71
+ with col2:
72
+ st.metric("Attempts", st.session_state.get('attempts_made', 'N/A'))
73
+ with col3:
74
+ st.metric("Interactive", st.session_state.get('interactive_enabled', 'N/A'))
75
+
76
+ if st.button("πŸ”„ Start New Generation"):
77
+ for key in ['initial_notes_generated', 'session_id', 'notes_content', 'notes_filename',
78
+ 'validation_score', 'attempts_made', 'interactive_enabled']:
79
+ if key in st.session_state:
80
+ del st.session_state[key]
81
+ st.rerun()
82
+
83
+ elif f and st.button("🎯 Generate Initial Notes", type="primary"):
84
+ with st.spinner("Generating initial notes..."):
85
+ url = f"{API_URL}/notes-llm"
86
+ if use_rlhf:
87
+ url += "?use_rlhf=true"
88
+
89
+ try:
90
+ resp = requests.post(url, files={"file": (f.name, f, f.type)})
91
+
92
+ if resp.status_code == 200:
93
+ new_session_id = resp.headers.get('X-Session-ID')
94
+ if new_session_id:
95
+ st.session_state['session_id'] = new_session_id
96
+ st.session_state['initial_notes_generated'] = True
97
+ st.session_state['notes_content'] = resp.content
98
+ st.session_state['notes_filename'] = "notes_initial.xlsx"
99
+ st.session_state['validation_score'] = resp.headers.get('X-Validation-Score', 'N/A')
100
+ st.session_state['attempts_made'] = resp.headers.get('X-Attempts-Made', 'N/A')
101
+ st.session_state['interactive_enabled'] = resp.headers.get('X-Interactive-Enabled', 'N/A')
102
+
103
+ cd = resp.headers.get("content-disposition", "")
104
+ if "filename=" in cd:
105
+ st.session_state['notes_filename'] = cd.split("filename=")[-1].strip().strip('"').strip("'")
106
+
107
+ st.success(f"βœ… Initial generation complete!")
108
+ st.info(f"πŸ“‹ Session ID: {new_session_id}")
109
+
110
+ st.download_button(
111
+ "πŸ“₯ Download Initial Notes",
112
+ data=resp.content,
113
+ file_name=st.session_state['notes_filename'],
114
+ mime=resp.headers.get("content-type", "application/octet-stream")
115
+ )
116
+
117
+ st.subheader("πŸ“Š Generation Info")
118
+ col1, col2, col3 = st.columns(3)
119
+ with col1:
120
+ st.metric("Validation Score", st.session_state['validation_score'])
121
+ with col2:
122
+ st.metric("Attempts", st.session_state['attempts_made'])
123
+ with col3:
124
+ st.metric("Interactive", st.session_state['interactive_enabled'])
125
+
126
+ else:
127
+ st.error(f"❌ Generation failed: {resp.text}")
128
+
129
+ except Exception as e:
130
+ st.error(f"❌ Error: {e}")
131
+
132
+ with tab2:
133
+ st.subheader("Submit Feedback for Improvement")
134
+
135
+ if not session_id:
136
+ st.warning("⚠ Please enter a Session ID from Step 1")
137
+ else:
138
+ feedback_text = st.text_area(
139
+ "πŸ’¬ Describe what you'd like to improve:",
140
+ placeholder="e.g., Add more detailed depreciation notes with asset categories",
141
+ height=100
142
+ )
143
+
144
+ feedback_type = st.selectbox(
145
+ "πŸ“‹ Feedback Type:",
146
+ ["text", "numeric", "formula", "suggestion"],
147
+ help="""
148
+ β€’ text: Additional explanations
149
+ β€’ numeric: Number-related changes
150
+ β€’ formula: Excel formulas
151
+ β€’ suggestion: General improvements
152
+ """
153
+ )
154
+
155
+ if st.button("πŸ“€ Submit Feedback", type="primary"):
156
+ if not feedback_text.strip():
157
+ st.error("❌ Please enter feedback text")
158
+ else:
159
+ with st.spinner("Submitting feedback..."):
160
+ try:
161
+ data = {
162
+ "session_id": session_id,
163
+ "feedback_text": feedback_text,
164
+ "feedback_type": feedback_type
165
+ }
166
+
167
+ resp = requests.post(f"{API_URL}/notes-llm/feedback", data=data)
168
+
169
+ if resp.status_code == 200:
170
+ result = resp.json()
171
+ st.success("βœ… Feedback submitted successfully!")
172
+ st.info(f"πŸ”’ Iteration: {result['iteration']}")
173
+ st.info(f"🏷 UDF Version: {result['udf_version']}")
174
+
175
+ st.info("πŸ’‘ Next: Go to 'Generate Improved' tab to see the enhancements!")
176
+
177
+ else:
178
+ st.error(f"❌ Feedback submission failed: {resp.text}")
179
+
180
+ except Exception as e:
181
+ st.error(f"❌ Error: {e}")
182
+
183
+ with tab3:
184
+ st.subheader("Generate Improved Notes")
185
+
186
+ if not session_id:
187
+ st.warning("⚠ Please enter a Session ID")
188
+ elif not f:
189
+ st.warning("⚠ Please upload the trial balance file again")
190
+ else:
191
+ improved_key = f"improved_notes_{session_id}"
192
+ if improved_key in st.session_state and st.session_state[improved_key]:
193
+ st.success("βœ… Improved notes have been generated!")
194
+
195
+ st.download_button(
196
+ "πŸ“₯ Download Improved Notes",
197
+ data=st.session_state[improved_key]['content'],
198
+ file_name=st.session_state[improved_key]['filename'],
199
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
200
+ )
201
+
202
+ col1, col2, col3 = st.columns(3)
203
+ with col1:
204
+ st.metric("Iteration", st.session_state[improved_key]['iteration'])
205
+ with col2:
206
+ st.metric("Feedbacks Applied", st.session_state[improved_key]['feedbacks_applied'])
207
+ with col3:
208
+ st.metric("UDFs Used", st.session_state[improved_key]['udfs_used'])
209
+
210
+ if st.button("πŸ”„ Regenerate Improved Notes"):
211
+ if improved_key in st.session_state:
212
+ del st.session_state[improved_key]
213
+ st.rerun()
214
+
215
+ else:
216
+ st.info("πŸ”„ This will apply all submitted feedback to generate improved notes")
217
+
218
+ if st.button("πŸš€ Generate Improved Notes", type="primary"):
219
+ with st.spinner("Applying feedback and generating improved notes..."):
220
+ try:
221
+ files = {"file": (f.name, f, f.type)}
222
+ data = {"session_id": session_id}
223
+
224
+ resp = requests.post(f"{API_URL}/notes-llm/generate",
225
+ files=files, data=data)
226
+
227
+ if resp.status_code == 200:
228
+ st.success("βœ… Improved notes generated!")
229
+
230
+ iteration = resp.headers.get('X-Iteration', '1')
231
+ filename = f"notes_improved_v{iteration}.xlsx"
232
+
233
+ st.session_state[improved_key] = {
234
+ 'content': resp.content,
235
+ 'filename': filename,
236
+ 'iteration': iteration,
237
+ 'feedbacks_applied': resp.headers.get('X-Feedbacks-Applied', 'N/A'),
238
+ 'udfs_used': resp.headers.get('X-UDFs-Archived', 'N/A')
239
+ }
240
+
241
+ col1, col2, col3 = st.columns(3)
242
+ with col1:
243
+ st.metric("Iteration", iteration)
244
+ with col2:
245
+ st.metric("Feedbacks Applied", st.session_state[improved_key]['feedbacks_applied'])
246
+ with col3:
247
+ st.metric("UDFs Used", st.session_state[improved_key]['udfs_used'])
248
+
249
+ st.download_button(
250
+ "πŸ“₯ Download Improved Notes",
251
+ data=resp.content,
252
+ file_name=filename,
253
+ mime=resp.headers.get("content-type", "application/octet-stream")
254
+ )
255
+
256
+ else:
257
+ st.error(f"❌ Generation failed: {resp.text}")
258
+
259
+ except Exception as e:
260
+ st.error(f"❌ Error: {e}")
261
+
262
+ with tab4:
263
+ st.subheader("Final Approval")
264
+
265
+ if not session_id:
266
+ st.warning("⚠ Please enter a Session ID")
267
+ else:
268
+ st.info("βœ… This will finalize the session and set the final UDF")
269
+ st.warning("⚠ After approval, no more feedback can be added to this session")
270
+
271
+ if st.button("🏁 Approve Final Result", type="primary"):
272
+ with st.spinner("Approving session..."):
273
+ try:
274
+ data = {"session_id": session_id}
275
+ resp = requests.post(f"{API_URL}/notes-llm/approve", data=data)
276
+
277
+ if resp.status_code == 200:
278
+ result = resp.json()
279
+ st.success("βœ… Session approved successfully!")
280
+ st.info(f"πŸ“‹ Session: {result['session_id']}")
281
+ st.info(f"🏷 Final UDF: {result['final_udf']}")
282
+
283
+ st.balloons()
284
+ st.success("πŸŽ‰ Interactive feedback session completed!")
285
+
286
+ else:
287
+ st.error(f"❌ Approval failed: {resp.text}")
288
+
289
+ except Exception as e:
290
+ st.error(f"❌ Error: {e}")
291
+
292
+ # Session History Sidebar
293
+ if session_id:
294
+ st.sidebar.subheader("πŸ“‹ Session History")
295
+ try:
296
+ resp = requests.get(f"{API_URL}/notes-llm/session/{session_id}")
297
+ if resp.status_code == 200:
298
+ session_data = resp.json()
299
+
300
+ st.sidebar.metric("Status", session_data['status'].upper())
301
+ st.sidebar.metric("Iterations", session_data['current_iteration'])
302
+ st.sidebar.metric("Feedbacks", len(session_data['feedback_history']))
303
+
304
+ if session_data['feedback_history']:
305
+ st.sidebar.subheader("Recent Feedback")
306
+ for fb in session_data['feedback_history'][-3:]:
307
+ st.sidebar.text(f"#{fb['iteration']}: {fb['feedback_type']}")
308
+ st.sidebar.caption(fb['feedback_text'][:50] + "...")
309
+
310
+ else:
311
+ st.sidebar.error("Session not found")
312
+ except Exception as e:
313
+ st.sidebar.error(f"Error loading session: {e}")
314
+
315
+ else:
316
+ # Standard endpoints: Balance Sheet, P&L, Cash Flow, Notes
317
+ st.header(f"{endpoint} Generation")
318
+ f = st.file_uploader("Upload Excel file", type=["xlsx"])
319
+
320
+ # Show RLHF option only for endpoints that support it
321
+ if endpoint != "Notes":
322
+ use_rlhf = st.checkbox("Use RLHF (Human Feedback Loop)?", value=False)
323
+ else:
324
+ use_rlhf = False
325
+ st.info("πŸ“ This is the simple notes generation endpoint (no RLHF/feedback)")
326
+
327
+ if f and st.button(f"Generate {endpoint}"):
328
+ endpoint_map = {
329
+ "Balance Sheet": "bs",
330
+ "Profit & Loss": "pnl",
331
+ "Cash Flow": "cf",
332
+ "Notes": "notes"
333
+ }
334
+ url = f"{API_URL}/{endpoint_map[endpoint]}"
335
+ if use_rlhf and endpoint != "Notes":
336
+ url += "?use_rlhf=true"
337
+
338
+ with st.spinner(f"Generating {endpoint}..."):
339
+ try:
340
+ resp = requests.post(url, files={"file": (f.name, f, f.type)})
341
+ if resp.status_code == 200:
342
+ cd = resp.headers.get("content-disposition", "")
343
+ filename = f"{endpoint_map[endpoint]}_output.xlsx"
344
+ if "filename=" in cd:
345
+ filename = cd.split("filename=")[-1].strip().strip('"').strip("'")
346
+
347
+ st.success(f"βœ… {endpoint} generated successfully!")
348
+ st.download_button(
349
+ f"πŸ“₯ Download {endpoint}",
350
+ data=resp.content,
351
+ file_name=filename,
352
+ mime=resp.headers.get("content-type", "application/octet-stream")
353
+ )
354
+
355
+ # Show RLHF metadata if available
356
+ if use_rlhf and endpoint != "Notes":
357
+ st.subheader("πŸ“Š RLHF Information")
358
+ col1, col2, col3 = st.columns(3)
359
+ with col1:
360
+ st.metric("Statement ID", resp.headers.get('X-RLHF-Statement-ID', 'N/A'))
361
+ with col2:
362
+ st.metric("Quality Score", resp.headers.get('X-RLHF-Quality-Score', 'N/A'))
363
+ with col3:
364
+ st.metric("Confidence", resp.headers.get('X-RLHF-Confidence', 'N/A'))
365
+ else:
366
+ st.error(f"❌ Generation failed: {resp.text}")
367
+ except Exception as e:
368
+ st.error(f"❌ Error: {e}")
369
+
370
+ elif main_section == "RLHF Management":
371
+ rlhf_endpoint = st.sidebar.selectbox(
372
+ "Choose RLHF Endpoint",
373
+ [
374
+ "Submit Feedback",
375
+ "Pending Reviews",
376
+ "Model Info",
377
+ "Stats",
378
+ "Manual Retrain",
379
+ "Review Statement"
380
+ ]
381
+ )
382
+
383
+ if rlhf_endpoint == "Submit Feedback":
384
+ st.header("πŸ“ Submit Text-Based RLHF Feedback")
385
+ st.info("πŸ’‘ This system focuses on qualitative text feedback instead of numeric scores")
386
+
387
+ statement_id = st.text_input("Statement ID", placeholder="Enter statement ID to review")
388
+ reviewer_id = st.text_input("Reviewer ID", value="streamlit_user")
389
+
390
+ st.subheader("πŸ“‹ Text-Based Feedback (Required)")
391
+ specific_errors = st.text_area(
392
+ "Specific Errors Found",
393
+ placeholder="Describe any specific errors, calculation mistakes, or inaccuracies...",
394
+ height=100
395
+ )
396
+ missing_items = st.text_area(
397
+ "Missing Items",
398
+ placeholder="List any items that should be included but are missing...",
399
+ height=100
400
+ )
401
+ improvement_suggestions = st.text_area(
402
+ "Improvement Suggestions",
403
+ placeholder="Provide specific suggestions for improvement...",
404
+ height=100
405
+ )
406
+
407
+ st.subheader("πŸ“Š Additional Information")
408
+ would_accept_for_audit = st.checkbox("Would Accept for Audit?", value=True)
409
+ complexity_level = st.selectbox("Complexity Level", ["low", "medium", "high"], index=1)
410
+
411
+ if st.button("πŸ“€ Submit Text-Based Feedback", type="primary"):
412
+ if not statement_id.strip():
413
+ st.error("❌ Please enter a Statement ID")
414
+ elif not any([specific_errors.strip(), missing_items.strip(), improvement_suggestions.strip()]):
415
+ st.error("❌ Please provide at least one type of text feedback")
416
+ else:
417
+ with st.spinner("Submitting feedback..."):
418
+ try:
419
+ data = {
420
+ "statement_id": statement_id,
421
+ "reviewer_id": reviewer_id,
422
+ "specific_errors": specific_errors,
423
+ "missing_items": missing_items,
424
+ "improvement_suggestions": improvement_suggestions,
425
+ "would_accept_for_audit": would_accept_for_audit,
426
+ "complexity_level": complexity_level
427
+ }
428
+ resp = requests.post(f"{API_URL}/rlhf/feedback", data=data)
429
+ if resp.status_code == 200:
430
+ st.success("βœ… Text-based feedback submitted successfully!")
431
+ result = resp.json()
432
+ st.json(result)
433
+ else:
434
+ st.error(f"❌ Submission failed: {resp.text}")
435
+ except Exception as e:
436
+ st.error(f"❌ Error: {e}")
437
+
438
+ elif rlhf_endpoint == "Pending Reviews":
439
+ st.header("πŸ“‹ Pending Reviews")
440
+ limit = st.number_input("Number of Reviews to Fetch", min_value=1, max_value=50, value=10)
441
+ if st.button("πŸ” Get Pending Reviews"):
442
+ try:
443
+ resp = requests.get(f"{API_URL}/rlhf/pending-reviews?limit={limit}")
444
+ if resp.status_code == 200:
445
+ data = resp.json()
446
+ if data.get('pending_reviews'):
447
+ st.success(f"Found {len(data['pending_reviews'])} pending reviews")
448
+ for review in data['pending_reviews']:
449
+ with st.expander(f"Statement ID: {review.get('statement_id', 'N/A')}"):
450
+ st.write(f"*Type:* {review.get('statement_type', 'N/A')}")
451
+ st.write(f"*Created:* {review.get('created_at', 'N/A')}")
452
+ if st.button(f"Review {review.get('statement_id', 'N/A')}", key=review.get('statement_id')):
453
+ st.info(f"Use 'Review Statement' tab with ID: {review.get('statement_id')}")
454
+ else:
455
+ st.info("No pending reviews found")
456
+ else:
457
+ st.error(f"Error: {resp.text}")
458
+ except Exception as e:
459
+ st.error(f"❌ Error: {e}")
460
+
461
+ elif rlhf_endpoint == "Model Info":
462
+ st.header("πŸ€– RLHF Model Information")
463
+ if st.button("πŸ“Š Get Model Info"):
464
+ try:
465
+ resp = requests.get(f"{API_URL}/rlhf/model-info")
466
+ if resp.status_code == 200:
467
+ data = resp.json()
468
+ st.success("βœ… Model information retrieved")
469
+
470
+ # Display key metrics
471
+ col1, col2, col3 = st.columns(3)
472
+ with col1:
473
+ st.metric("Total Feedback", data.get('total_feedback_count', 'N/A'))
474
+ with col2:
475
+ st.metric("Model Type", data.get('model_type', 'N/A'))
476
+ with col3:
477
+ st.metric("Last Updated", data.get('last_updated', 'N/A'))
478
+
479
+ st.json(data)
480
+ else:
481
+ st.error(f"Error: {resp.text}")
482
+ except Exception as e:
483
+ st.error(f"❌ Error: {e}")
484
+
485
+ elif rlhf_endpoint == "Stats":
486
+ st.header("πŸ“ˆ RLHF Statistics")
487
+ if st.button("πŸ“Š Get RLHF Stats"):
488
+ try:
489
+ resp = requests.get(f"{API_URL}/rlhf/stats")
490
+ if resp.status_code == 200:
491
+ data = resp.json()
492
+ st.success("βœ… Statistics retrieved")
493
+
494
+ # Display key stats
495
+ if 'feedback_stats' in data:
496
+ stats = data['feedback_stats']
497
+ col1, col2, col3, col4 = st.columns(4)
498
+ with col1:
499
+ st.metric("Total Feedback", stats.get('total_feedback', 'N/A'))
500
+ with col2:
501
+ st.metric("Unique Reviewers", stats.get('unique_reviewers', 'N/A'))
502
+ with col3:
503
+ st.metric("Acceptance Rate", f"{stats.get('acceptance_rate', 0):.1%}")
504
+ with col4:
505
+ st.metric("Avg Complexity", stats.get('avg_complexity_score', 'N/A'))
506
+
507
+ st.json(data)
508
+ else:
509
+ st.error(f"Error: {resp.text}")
510
+ except Exception as e:
511
+ st.error(f"❌ Error: {e}")
512
+
513
+ elif rlhf_endpoint == "Manual Retrain":
514
+ st.header("πŸ”„ Manual RLHF Retrain")
515
+ st.info("πŸ’‘ This will analyze current feedback patterns (no ML training involved)")
516
+ if st.button("πŸš€ Trigger Retrain", type="primary"):
517
+ try:
518
+ resp = requests.post(f"{API_URL}/rlhf/retrain")
519
+ if resp.status_code == 200:
520
+ st.success("βœ… Retrain completed successfully!")
521
+ st.json(resp.json())
522
+ else:
523
+ st.error(f"Error: {resp.text}")
524
+ except Exception as e:
525
+ st.error(f"❌ Error: {e}")
526
+
527
+ elif rlhf_endpoint == "Review Statement":
528
+ st.header("πŸ” Review Specific Statement")
529
+ statement_id = st.text_input("Statement ID", placeholder="Enter statement ID to review")
530
+ if statement_id and st.button("πŸ“‹ Get Review Form"):
531
+ try:
532
+ resp = requests.get(f"{API_URL}/rlhf/review/{statement_id}")
533
+ if resp.status_code == 200:
534
+ if "text/html" in resp.headers.get("content-type", ""):
535
+ st.success("βœ… Review form loaded")
536
+ st.components.v1.html(resp.text, height=800, scrolling=True)
537
+ else:
538
+ st.json(resp.json())
539
+ else:
540
+ st.error(f"Statement not found: {resp.text}")
541
+ except Exception as e:
542
+ st.error(f"❌ Error: {e}")
543
+
544
+ # Clear session button
545
+ if st.sidebar.button("πŸ—‘ Clear All Session Data"):
546
+ for key in list(st.session_state.keys()):
547
+ del st.session_state[key]
548
+ st.sidebar.success("βœ… Session data cleared!")
549
+ st.rerun()
550
+
551
+ st.caption("FinRyver Financial Statements Generator with Interactive Feedback & RLHF Support")