From 7303008f48ec3a1547cd855f653d7f853405027f Mon Sep 17 00:00:00 2001 From: Jeason <1710884619@qq.com> Date: Mon, 20 Apr 2026 10:04:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E4=BA=86=20evidence=20=E6=8D=95?= =?UTF-8?q?=E8=8E=B7=E7=9A=84=E4=BC=98=E5=85=88=E7=BA=A7=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- start_web.bat | 2 +- utils/code_executor.py | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/start_web.bat b/start_web.bat index 50ba277..50a780f 100644 --- a/start_web.bat +++ b/start_web.bat @@ -1,5 +1,5 @@ @echo off echo Starting IOV Data Analysis Agent Web Interface... echo Please open http://localhost:8000 in your browser. -python -m uvicorn web.main:app --reload --host 0.0.0.0 --port 8000 +python -m uvicorn web.main:app --reload --reload-exclude "outputs/*" --host 0.0.0.0 --port 8000 pause diff --git a/utils/code_executor.py b/utils/code_executor.py index d867d7e..fca981d 100644 --- a/utils/code_executor.py +++ b/utils/code_executor.py @@ -387,10 +387,14 @@ from IPython.display import display sanitized.append(clean) return sanitized - def _capture_evidence_rows(self, result, shell) -> List[Dict]: + def _capture_evidence_rows(self, result, shell, df_snapshot_before=None) -> List[Dict]: """ Capture up to 10 evidence rows from the execution result. - First checks result.result, then falls back to the last DataFrame in namespace. + + Priority order: + 1. result.result if it's a DataFrame (direct code output) + 2. Smallest newly-created DataFrame this round (most likely an analysis result) + 3. Last DataFrame in namespace (fallback) """ try: # Primary: check if result.result is a DataFrame @@ -401,6 +405,31 @@ from IPython.display import display except Exception: pass + # Secondary: find the smallest NEW DataFrame created this round + # (e.g. groupby result, crosstab, etc. — more relevant than the main df) + if df_snapshot_before is not None: + try: + after = self._snapshot_dataframes(shell) + new_names = [n for n in after if n not in df_snapshot_before] + if new_names: + # Pick the smallest new DataFrame (most likely a summary/aggregation) + best_df = None + best_size = float('inf') + for name in new_names: + try: + obj = shell.user_ns[name] + if isinstance(obj, pd.DataFrame) and len(obj) < best_size: + best_df = obj + best_size = len(obj) + except Exception: + continue + if best_df is not None: + return self._sanitize_for_json( + best_df.head(10).to_dict(orient="records") + ) + except Exception: + pass + # Fallback: find the last-assigned DataFrame variable in namespace try: last_df = None @@ -634,7 +663,7 @@ from IPython.display import display # --- 自动保存机制 end --- # --- Task 5: Evidence capture --- - evidence_rows = self._capture_evidence_rows(result, self.shell) + evidence_rows = self._capture_evidence_rows(result, self.shell, df_snapshot_before) # --- Task 6.2-6.4: DataFrame auto-detection and export --- auto_exported_files = []