DocUA commited on
Commit
82ca3ff
·
1 Parent(s): 353a6ce

Enhance CSV export functionality by extracting reasoning from notes and streamline file upload interface to support only CSV format

Browse files
src/core/verification_csv_exporter.py CHANGED
@@ -8,6 +8,8 @@ including tagging data, generated content, interaction logs, and error statistic
8
 
9
  import csv
10
  import io
 
 
11
  from datetime import datetime
12
  from typing import List, Optional, Dict, Any
13
  from src.core.verification_models import VerificationRecord, VerificationSession
@@ -22,6 +24,36 @@ from src.core.error_pattern_analyzer import ErrorPatternAnalyzer
22
  class VerificationCSVExporter:
23
  """Exports verification sessions to CSV format."""
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  @staticmethod
26
  def generate_csv_content(session: VerificationSession) -> str:
27
  """
@@ -74,7 +106,7 @@ class VerificationCSVExporter:
74
  record.original_message,
75
  classifier_decision,
76
  ground_truth,
77
- record.verifier_notes,
78
  timestamp,
79
  ])
80
 
@@ -205,7 +237,7 @@ class VerificationCSVExporter:
205
  record.original_message,
206
  classifier_decision,
207
  ground_truth,
208
- record.verifier_notes,
209
  timestamp,
210
  ])
211
 
 
8
 
9
  import csv
10
  import io
11
+ import json
12
+ import re
13
  from datetime import datetime
14
  from typing import List, Optional, Dict, Any
15
  from src.core.verification_models import VerificationRecord, VerificationSession
 
24
  class VerificationCSVExporter:
25
  """Exports verification sessions to CSV format."""
26
 
27
+ @staticmethod
28
+ def _extract_reasoning(notes: str) -> str:
29
+ """Extract `reasoning` from notes when notes contain JSON.
30
+
31
+ Supports:
32
+ - fenced blocks: ```json { ... } ```
33
+ - plain JSON objects: { ... }
34
+
35
+ If parsing fails or `reasoning` is missing, returns the original notes.
36
+ """
37
+ if not notes:
38
+ return ""
39
+
40
+ raw = notes.strip()
41
+
42
+ # Remove fenced code block wrapper if present
43
+ m = re.search(r"```(?:json)?\s*(\{.*\})\s*```", raw, flags=re.DOTALL | re.IGNORECASE)
44
+ json_str = m.group(1).strip() if m else raw
45
+
46
+ # Very lightweight check to avoid exceptions on non-JSON notes
47
+ if not (json_str.startswith("{") and json_str.endswith("}")):
48
+ return raw
49
+
50
+ try:
51
+ payload = json.loads(json_str)
52
+ reasoning = payload.get("reasoning")
53
+ return reasoning.strip() if isinstance(reasoning, str) and reasoning.strip() else raw
54
+ except Exception:
55
+ return raw
56
+
57
  @staticmethod
58
  def generate_csv_content(session: VerificationSession) -> str:
59
  """
 
106
  record.original_message,
107
  classifier_decision,
108
  ground_truth,
109
+ VerificationCSVExporter._extract_reasoning(record.verifier_notes),
110
  timestamp,
111
  ])
112
 
 
237
  record.original_message,
238
  classifier_decision,
239
  ground_truth,
240
+ VerificationCSVExporter._extract_reasoning(record.verifier_notes),
241
  timestamp,
242
  ])
243
 
src/interface/file_upload_interface.py CHANGED
@@ -1,9 +1,8 @@
1
  # file_upload_interface.py
2
- """
3
- File Upload Interface for Enhanced Verification Modes.
4
 
5
- Provides interface for uploading CSV/XLSX files, validating content,
6
- batch processing with progress tracking, and comprehensive export options.
7
 
8
  Requirements: 4.1, 4.3, 4.4, 4.5, 4.6, 4.7, 12.1, 12.2, 12.3, 12.4, 12.5
9
  """
@@ -61,7 +60,7 @@ class FileUploadInterfaceController(ProgressTrackingMixin):
61
  Returns:
62
  Tuple of (success, status_message, file_result, preview_html)
63
  """
64
- if not file_path:
65
  return False, "❌ No file uploaded", None, ""
66
 
67
  try:
@@ -570,7 +569,7 @@ class FileUploadInterfaceController(ProgressTrackingMixin):
570
  Export batch processing results.
571
 
572
  Args:
573
- format_type: Export format ("csv", "xlsx", "json")
574
 
575
  Returns:
576
  Tuple of (success, message, file_path)
@@ -586,13 +585,6 @@ class FileUploadInterfaceController(ProgressTrackingMixin):
586
  temp_file.write(content)
587
  temp_file.close()
588
  file_path = temp_file.name
589
- elif format_type == "xlsx":
590
- content = self.store.export_to_xlsx(self.current_session.session_id)
591
- # Save to temporary file
592
- temp_file = tempfile.NamedTemporaryFile(mode='wb', suffix='.xlsx', delete=False)
593
- temp_file.write(content)
594
- temp_file.close()
595
- file_path = temp_file.name
596
  elif format_type == "json":
597
  content = self.store.export_to_json(self.current_session.session_id)
598
  # Save to temporary file
@@ -687,7 +679,7 @@ class FileUploadInterfaceController(ProgressTrackingMixin):
687
  - Processing Speed: {self.progress_tracker.get_processing_speed_display() if hasattr(self, 'progress_tracker') else 'Unknown'}
688
  """
689
 
690
- def get_template_files(self) -> Tuple[str, bytes]:
691
  """
692
  Get template files for download.
693
 
@@ -695,7 +687,7 @@ class FileUploadInterfaceController(ProgressTrackingMixin):
695
  Tuple of (csv_content, xlsx_bytes)
696
  """
697
  csv_content = self.file_processor.generate_csv_template()
698
- xlsx_bytes = self.file_processor.generate_xlsx_template()
699
  return csv_content, xlsx_bytes
700
 
701
 
@@ -721,8 +713,8 @@ def create_file_upload_interface() -> gr.Blocks:
721
  gr.Markdown("## 📤 Upload Test File")
722
 
723
  file_upload = gr.File(
724
- label="Select CSV or XLSX File",
725
- file_types=[".csv", ".xlsx"],
726
  type="filepath"
727
  )
728
 
@@ -744,20 +736,7 @@ def create_file_upload_interface() -> gr.Blocks:
744
  size="sm"
745
  )
746
 
747
- # Generate XLSX template on demand
748
- def generate_xlsx_template_file():
749
- """Generate XLSX template and return file path."""
750
- xlsx_content = controller.file_processor.generate_xlsx_template()
751
- temp_path = os.path.join(tempfile.gettempdir(), "template_test_messages.xlsx")
752
- with open(temp_path, "wb") as f:
753
- f.write(xlsx_content)
754
- return temp_path
755
-
756
- download_xlsx_template_btn = gr.DownloadButton(
757
- "📊 Download XLSX Template",
758
- value=generate_xlsx_template_file,
759
- size="sm"
760
- )
761
 
762
  gr.Markdown("### 📝 Format Requirements")
763
  gr.Markdown("""
@@ -772,7 +751,6 @@ def create_file_upload_interface() -> gr.Blocks:
772
 
773
  **Supported formats:**
774
  - CSV with comma, semicolon, or tab delimiters
775
- - XLSX files (first worksheet only)
776
  """)
777
 
778
  # File processing results section
@@ -807,16 +785,16 @@ def create_file_upload_interface() -> gr.Blocks:
807
  "🚀",
808
  "lg"
809
  )
810
-
811
- # Progress display
 
 
 
812
  batch_progress_display = gr.Markdown(
813
  "Ready to start batch processing",
814
  label="Progress"
815
  )
816
 
817
- # Visual progress bar (updates during batch classification)
818
- batch_progress_bar = gr.Progress()
819
-
820
  # Export results (visible after batch completes)
821
  gr.Markdown("### 💾 Download Results")
822
  with gr.Row():
@@ -830,11 +808,6 @@ def create_file_upload_interface() -> gr.Blocks:
830
  variant="secondary",
831
  visible=False,
832
  )
833
- export_xlsx_btn = gr.DownloadButton(
834
- label="Download XLSX",
835
- variant="secondary",
836
- visible=False,
837
- )
838
 
839
  # Message processing section (initially hidden)
840
  message_processing_section = gr.Row(visible=False)
@@ -957,7 +930,6 @@ def create_file_upload_interface() -> gr.Blocks:
957
  None, # current_session_state
958
  gr.DownloadButton(visible=False), # export_csv_btn
959
  gr.DownloadButton(visible=False), # export_json_btn
960
- gr.DownloadButton(visible=False), # export_xlsx_btn
961
  "File cleared" # status_message
962
  )
963
 
@@ -989,7 +961,6 @@ def create_file_upload_interface() -> gr.Blocks:
989
  progress_text, # batch_progress_display
990
  gr.DownloadButton(visible=True), # export_csv_btn
991
  gr.DownloadButton(visible=True), # export_json_btn
992
- gr.DownloadButton(visible=True), # export_xlsx_btn
993
  run_msg # status_message
994
  )
995
 
@@ -1004,7 +975,6 @@ def create_file_upload_interface() -> gr.Blocks:
1004
  "❌ Batch classification failed", # batch_progress_display
1005
  gr.DownloadButton(visible=False), # export_csv_btn
1006
  gr.DownloadButton(visible=False), # export_json_btn
1007
- gr.DownloadButton(visible=False), # export_xlsx_btn
1008
  run_msg # status_message
1009
  )
1010
  else:
@@ -1019,7 +989,6 @@ def create_file_upload_interface() -> gr.Blocks:
1019
  "", # batch_progress_display
1020
  gr.DownloadButton(visible=False), # export_csv_btn
1021
  gr.DownloadButton(visible=False), # export_json_btn
1022
- gr.DownloadButton(visible=False), # export_xlsx_btn
1023
  message # status_message
1024
  )
1025
 
@@ -1058,7 +1027,6 @@ def create_file_upload_interface() -> gr.Blocks:
1058
  gr.Row(visible=False), # correction_section
1059
  gr.DownloadButton(visible=True), # export_csv_btn
1060
  gr.DownloadButton(visible=True), # export_json_btn
1061
- gr.DownloadButton(visible=True), # export_xlsx_btn
1062
  message # status_message
1063
  )
1064
  else:
@@ -1081,7 +1049,6 @@ def create_file_upload_interface() -> gr.Blocks:
1081
  gr.Row(visible=False), # correction_section
1082
  gr.DownloadButton(visible=True), # export_csv_btn
1083
  gr.DownloadButton(visible=True), # export_json_btn
1084
- gr.DownloadButton(visible=True), # export_xlsx_btn
1085
  message # status_message
1086
  )
1087
  else:
@@ -1096,7 +1063,6 @@ def create_file_upload_interface() -> gr.Blocks:
1096
  gr.Row(visible=False), # correction_section
1097
  gr.DownloadButton(visible=False), # export_csv_btn
1098
  gr.DownloadButton(visible=False), # export_json_btn
1099
- gr.DownloadButton(visible=False), # export_xlsx_btn
1100
  message # status_message
1101
  )
1102
 
@@ -1145,7 +1111,6 @@ def create_file_upload_interface() -> gr.Blocks:
1145
  "", # correction_notes (clear)
1146
  gr.DownloadButton(visible=True), # export_csv_btn
1147
  gr.DownloadButton(visible=True), # export_json_btn
1148
- gr.DownloadButton(visible=True), # export_xlsx_btn
1149
  message # status_message
1150
  )
1151
  else:
@@ -1169,7 +1134,6 @@ def create_file_upload_interface() -> gr.Blocks:
1169
  "", # correction_notes (clear)
1170
  gr.DownloadButton(visible=True), # export_csv_btn
1171
  gr.DownloadButton(visible=True), # export_json_btn
1172
- gr.DownloadButton(visible=True), # export_xlsx_btn
1173
  message # status_message
1174
  )
1175
  else:
@@ -1185,7 +1149,6 @@ def create_file_upload_interface() -> gr.Blocks:
1185
  notes, # correction_notes (keep)
1186
  gr.DownloadButton(visible=False), # export_csv_btn
1187
  gr.DownloadButton(visible=False), # export_json_btn
1188
- gr.DownloadButton(visible=False), # export_xlsx_btn
1189
  message # status_message
1190
  )
1191
 
@@ -1207,17 +1170,6 @@ def create_file_upload_interface() -> gr.Blocks:
1207
 
1208
  return temp_file.name
1209
 
1210
- def on_download_xlsx_template():
1211
- """Handle XLSX template download."""
1212
- _, xlsx_bytes = controller.get_template_files()
1213
-
1214
- # Create temporary file
1215
- temp_file = tempfile.NamedTemporaryFile(mode='wb', suffix='.xlsx', delete=False)
1216
- temp_file.write(xlsx_bytes)
1217
- temp_file.close()
1218
-
1219
- return temp_file.name
1220
-
1221
  # Bind event handlers
1222
  process_file_btn.click(
1223
  on_process_file,
@@ -1242,7 +1194,6 @@ def create_file_upload_interface() -> gr.Blocks:
1242
  current_session_state,
1243
  export_csv_btn,
1244
  export_json_btn,
1245
- export_xlsx_btn,
1246
  status_message
1247
  ]
1248
  )
@@ -1261,7 +1212,6 @@ def create_file_upload_interface() -> gr.Blocks:
1261
  batch_progress_display,
1262
  export_csv_btn,
1263
  export_json_btn,
1264
- export_xlsx_btn,
1265
  status_message
1266
  ]
1267
  )
@@ -1279,7 +1229,6 @@ def create_file_upload_interface() -> gr.Blocks:
1279
  correction_section,
1280
  export_csv_btn,
1281
  export_json_btn,
1282
- export_xlsx_btn,
1283
  status_message
1284
  ]
1285
  )
@@ -1304,23 +1253,18 @@ def create_file_upload_interface() -> gr.Blocks:
1304
  correction_notes,
1305
  export_csv_btn,
1306
  export_json_btn,
1307
- export_xlsx_btn,
1308
  status_message
1309
  ]
1310
  )
1311
 
1312
  export_csv_btn.click(lambda: on_export_results_file("csv"), outputs=[export_csv_btn])
1313
  export_json_btn.click(lambda: on_export_results_file("json"), outputs=[export_json_btn])
1314
- export_xlsx_btn.click(lambda: on_export_results_file("xlsx"), outputs=[export_xlsx_btn])
1315
 
1316
  download_csv_template_btn.click(
1317
  on_download_csv_template,
1318
  outputs=[gr.File(visible=False)]
1319
  )
1320
 
1321
- download_xlsx_template_btn.click(
1322
- on_download_xlsx_template,
1323
- outputs=[gr.File(visible=False)]
1324
- )
1325
 
1326
  return file_upload_interface
 
1
  # file_upload_interface.py
2
+ """File Upload Interface for Enhanced Verification Modes.
 
3
 
4
+ Provides interface for uploading CSV files, validating content,
5
+ batch processing with progress tracking, and exporting results.
6
 
7
  Requirements: 4.1, 4.3, 4.4, 4.5, 4.6, 4.7, 12.1, 12.2, 12.3, 12.4, 12.5
8
  """
 
60
  Returns:
61
  Tuple of (success, status_message, file_result, preview_html)
62
  """
63
+ if not file_path or not file_path.endswith('.csv'):
64
  return False, "❌ No file uploaded", None, ""
65
 
66
  try:
 
569
  Export batch processing results.
570
 
571
  Args:
572
+ format_type: Export format ("csv", "json")
573
 
574
  Returns:
575
  Tuple of (success, message, file_path)
 
585
  temp_file.write(content)
586
  temp_file.close()
587
  file_path = temp_file.name
 
 
 
 
 
 
 
588
  elif format_type == "json":
589
  content = self.store.export_to_json(self.current_session.session_id)
590
  # Save to temporary file
 
679
  - Processing Speed: {self.progress_tracker.get_processing_speed_display() if hasattr(self, 'progress_tracker') else 'Unknown'}
680
  """
681
 
682
+ def get_template_files(self) -> Tuple[str, Optional[bytes]]:
683
  """
684
  Get template files for download.
685
 
 
687
  Tuple of (csv_content, xlsx_bytes)
688
  """
689
  csv_content = self.file_processor.generate_csv_template()
690
+ xlsx_bytes = None # Removed XLSX template generation
691
  return csv_content, xlsx_bytes
692
 
693
 
 
713
  gr.Markdown("## 📤 Upload Test File")
714
 
715
  file_upload = gr.File(
716
+ label="Select CSV File",
717
+ file_types=[".csv"],
718
  type="filepath"
719
  )
720
 
 
736
  size="sm"
737
  )
738
 
739
+ # XLSX template removed (CSV-only workflow)
 
 
 
 
 
 
 
 
 
 
 
 
 
740
 
741
  gr.Markdown("### 📝 Format Requirements")
742
  gr.Markdown("""
 
751
 
752
  **Supported formats:**
753
  - CSV with comma, semicolon, or tab delimiters
 
754
  """)
755
 
756
  # File processing results section
 
785
  "🚀",
786
  "lg"
787
  )
788
+
789
+ # Visual progress bar (updates during batch classification)
790
+ batch_progress_bar = gr.Progress()
791
+
792
+ # Progress text display
793
  batch_progress_display = gr.Markdown(
794
  "Ready to start batch processing",
795
  label="Progress"
796
  )
797
 
 
 
 
798
  # Export results (visible after batch completes)
799
  gr.Markdown("### 💾 Download Results")
800
  with gr.Row():
 
808
  variant="secondary",
809
  visible=False,
810
  )
 
 
 
 
 
811
 
812
  # Message processing section (initially hidden)
813
  message_processing_section = gr.Row(visible=False)
 
930
  None, # current_session_state
931
  gr.DownloadButton(visible=False), # export_csv_btn
932
  gr.DownloadButton(visible=False), # export_json_btn
 
933
  "File cleared" # status_message
934
  )
935
 
 
961
  progress_text, # batch_progress_display
962
  gr.DownloadButton(visible=True), # export_csv_btn
963
  gr.DownloadButton(visible=True), # export_json_btn
 
964
  run_msg # status_message
965
  )
966
 
 
975
  "❌ Batch classification failed", # batch_progress_display
976
  gr.DownloadButton(visible=False), # export_csv_btn
977
  gr.DownloadButton(visible=False), # export_json_btn
 
978
  run_msg # status_message
979
  )
980
  else:
 
989
  "", # batch_progress_display
990
  gr.DownloadButton(visible=False), # export_csv_btn
991
  gr.DownloadButton(visible=False), # export_json_btn
 
992
  message # status_message
993
  )
994
 
 
1027
  gr.Row(visible=False), # correction_section
1028
  gr.DownloadButton(visible=True), # export_csv_btn
1029
  gr.DownloadButton(visible=True), # export_json_btn
 
1030
  message # status_message
1031
  )
1032
  else:
 
1049
  gr.Row(visible=False), # correction_section
1050
  gr.DownloadButton(visible=True), # export_csv_btn
1051
  gr.DownloadButton(visible=True), # export_json_btn
 
1052
  message # status_message
1053
  )
1054
  else:
 
1063
  gr.Row(visible=False), # correction_section
1064
  gr.DownloadButton(visible=False), # export_csv_btn
1065
  gr.DownloadButton(visible=False), # export_json_btn
 
1066
  message # status_message
1067
  )
1068
 
 
1111
  "", # correction_notes (clear)
1112
  gr.DownloadButton(visible=True), # export_csv_btn
1113
  gr.DownloadButton(visible=True), # export_json_btn
 
1114
  message # status_message
1115
  )
1116
  else:
 
1134
  "", # correction_notes (clear)
1135
  gr.DownloadButton(visible=True), # export_csv_btn
1136
  gr.DownloadButton(visible=True), # export_json_btn
 
1137
  message # status_message
1138
  )
1139
  else:
 
1149
  notes, # correction_notes (keep)
1150
  gr.DownloadButton(visible=False), # export_csv_btn
1151
  gr.DownloadButton(visible=False), # export_json_btn
 
1152
  message # status_message
1153
  )
1154
 
 
1170
 
1171
  return temp_file.name
1172
 
 
 
 
 
 
 
 
 
 
 
 
1173
  # Bind event handlers
1174
  process_file_btn.click(
1175
  on_process_file,
 
1194
  current_session_state,
1195
  export_csv_btn,
1196
  export_json_btn,
 
1197
  status_message
1198
  ]
1199
  )
 
1212
  batch_progress_display,
1213
  export_csv_btn,
1214
  export_json_btn,
 
1215
  status_message
1216
  ]
1217
  )
 
1229
  correction_section,
1230
  export_csv_btn,
1231
  export_json_btn,
 
1232
  status_message
1233
  ]
1234
  )
 
1253
  correction_notes,
1254
  export_csv_btn,
1255
  export_json_btn,
 
1256
  status_message
1257
  ]
1258
  )
1259
 
1260
  export_csv_btn.click(lambda: on_export_results_file("csv"), outputs=[export_csv_btn])
1261
  export_json_btn.click(lambda: on_export_results_file("json"), outputs=[export_json_btn])
 
1262
 
1263
  download_csv_template_btn.click(
1264
  on_download_csv_template,
1265
  outputs=[gr.File(visible=False)]
1266
  )
1267
 
1268
+
 
 
 
1269
 
1270
  return file_upload_interface