linxinhua commited on
Commit
0247dca
·
verified ·
1 Parent(s): 6ce256d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -136
app.py CHANGED
@@ -12,29 +12,25 @@ class DataManager:
12
  def __init__(self, token=None):
13
  self.repo_id = "CIV3283/Data_Storage"
14
  self.branch = "data_branch"
 
15
 
16
- # Use provided token first, otherwise get from environment variable
17
- self.token = token or os.getenv('CIV3283_access')
18
-
19
- # Authenticate if token is available
20
  if self.token:
21
  try:
22
  login(token=self.token)
23
- print("✅ Authentication successful")
24
  except Exception as e:
25
- print(f"❌ Authentication failed: {e}")
26
 
27
  self.api = HfApi(token=self.token)
28
 
29
  def get_available_files(self) -> Tuple[List[str], List[str]]:
30
- """Get all available feedback and query files"""
31
  try:
32
- # Try to get all files from repository
33
  repo_files = self.api.list_repo_files(
34
  repo_id=self.repo_id,
35
- revision=self.branch,
36
- token=self.token,
37
- repo_type="space" # Explicitly specify this is a space
38
  )
39
 
40
  feedback_files = []
@@ -49,67 +45,48 @@ class DataManager:
49
  return sorted(feedback_files), sorted(query_files)
50
 
51
  except Exception as e:
52
- print(f"❌ Error getting file list: {e}")
53
- # If API call fails, try to generate possible filename list
54
- return self._generate_possible_filenames()
55
-
56
- def _generate_possible_filenames(self) -> Tuple[List[str], List[str]]:
57
- """Generate possible filename list as backup"""
58
- feedback_files = []
59
- query_files = []
60
-
61
- # Generate all possible filenames from 01 to 95
62
- for i in range(1, 96):
63
- student_id = f"{i:02d}" # Format as two digits
64
- feedback_file = f"CIV3283_Student_{student_id}_feedback_log.csv"
65
- query_file = f"CIV3283_Student_{student_id}_query_log.csv"
66
- feedback_files.append(feedback_file)
67
- query_files.append(query_file)
68
-
69
- return feedback_files, query_files
70
 
71
  def download_and_read_csv(self, filename: str) -> pd.DataFrame:
72
- """Download and read CSV file"""
73
  try:
74
- # Download file to temporary location
75
  local_file = hf_hub_download(
76
  repo_id=self.repo_id,
77
  filename=filename,
78
  revision=self.branch,
79
- repo_type="space",
80
- token=self.token,
81
  cache_dir=tempfile.gettempdir()
82
  )
83
 
84
- # Read CSV
85
  df = pd.read_csv(local_file)
86
 
87
- # Ensure timestamp column exists and convert to datetime
88
  if 'timestamp' in df.columns:
89
  df['timestamp'] = pd.to_datetime(df['timestamp'])
90
 
91
  return df
92
 
93
  except Exception as e:
94
- print(f"❌ Failed to read file {filename}: {e}")
95
- # Return empty DataFrame rather than complete failure
96
  return pd.DataFrame()
97
 
98
  def filter_data_by_date(self, df: pd.DataFrame, start_date: str, end_date: str) -> pd.DataFrame:
99
- """Filter data by date range"""
100
  if df.empty or 'timestamp' not in df.columns:
101
  return df
102
 
103
  try:
104
- # Convert input date strings
105
  start_dt = pd.to_datetime(start_date)
106
 
107
- if end_date == "now":
108
  end_dt = pd.Timestamp.now()
109
  else:
110
- end_dt = pd.to_datetime(end_date) + timedelta(days=1) - timedelta(seconds=1) # Include full day
111
 
112
- # Filter data
113
  mask = (df['timestamp'] >= start_dt) & (df['timestamp'] <= end_dt)
114
  return df[mask]
115
 
@@ -118,21 +95,21 @@ class DataManager:
118
  return df
119
 
120
  def process_files(self, file_type: str, start_date: str, end_date: str) -> Tuple[str, str, str]:
121
- """Process files and generate download content"""
122
  feedback_files, query_files = self.get_available_files()
123
 
124
  result_data = []
125
  file_info = []
126
  total_records = 0
127
 
128
- # Determine files to process based on selected file type
129
  files_to_process = []
130
- if file_type in ["Feedback Files", "Both"]:
131
  files_to_process.extend([(f, "feedback") for f in feedback_files])
132
- if file_type in ["Query Files", "Both"]:
133
  files_to_process.extend([(f, "query") for f in query_files])
134
 
135
- # Process each file
136
  for filename, ftype in files_to_process:
137
  df = self.download_and_read_csv(filename)
138
  if not df.empty:
@@ -144,56 +121,41 @@ class DataManager:
144
  result_data.append(filtered_df)
145
  total_records += filtered_count
146
 
147
- file_info.append(f"{filename}: {original_count} records → {filtered_count} matching criteria")
148
 
149
- # Combine all data
150
  if result_data:
151
  combined_df = pd.concat(result_data, ignore_index=True)
152
 
153
- # Generate CSV content
154
  csv_buffer = io.StringIO()
155
  combined_df.to_csv(csv_buffer, index=False, encoding='utf-8')
156
  csv_content = csv_buffer.getvalue()
157
 
158
- # Generate filename with type and date info
159
- end_date_str = "now" if end_date == "now" else end_date
160
- type_str = file_type.lower().replace(" ", "_")
161
- filename = f"CIV3283_data_export_{type_str}_{start_date}_to_{end_date_str}.csv"
162
 
163
- # Generate status info
164
- status = f"✅ Successfully processed {len(files_to_process)} files\n"
165
- status += f"📊 Total records found: {total_records}\n"
166
- status += f"📅 Date range: {start_date} to {end_date_str}\n\n"
167
- status += "File details:\n" + "\n".join(file_info)
168
 
169
  return csv_content, filename, status
170
  else:
171
- return "", "", "❌ No matching data found"
172
-
173
- # Global variable to store data manager
174
- data_manager = None
175
 
176
- def initialize_data_manager(hf_token=None):
177
- """Initialize data manager"""
178
- global data_manager
179
- data_manager = DataManager(token=hf_token)
180
- return data_manager
181
 
182
- def process_and_download(file_type, start_date, end_date, hf_token):
183
- """Process request and return download file"""
184
  try:
185
- # Ensure data manager is initialized
186
- global data_manager
187
- env_token = os.getenv('CIV3283_access')
188
- current_token = hf_token or env_token
189
-
190
- if data_manager is None or data_manager.token != current_token:
191
- data_manager = initialize_data_manager(current_token)
192
-
193
  csv_content, filename, status = data_manager.process_files(file_type, start_date, end_date)
194
 
195
  if csv_content:
196
- # Create temporary file
197
  temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False, encoding='utf-8')
198
  temp_file.write(csv_content)
199
  temp_file.close()
@@ -203,35 +165,19 @@ def process_and_download(file_type, start_date, end_date, hf_token):
203
  return status, None, None
204
 
205
  except Exception as e:
206
- return f"❌ Error occurred during processing: {str(e)}", None, None
207
 
208
- def get_file_summary(hf_token=None):
209
- """Get file overview"""
210
  try:
211
- # If not initialized or token changed, reinitialize
212
- global data_manager
213
- env_token = os.getenv('CIV3283_access')
214
- current_token = hf_token or env_token
215
-
216
- if data_manager is None or data_manager.token != current_token:
217
- data_manager = initialize_data_manager(current_token)
218
-
219
  feedback_files, query_files = data_manager.get_available_files()
220
- summary = f"📁 Currently available files:\n"
221
- summary += f" Feedback files: {len(feedback_files)}\n"
222
- summary += f" Query files: {len(query_files)}\n"
223
- summary += f" Total: {len(feedback_files) + len(query_files)} files"
224
-
225
- if env_token:
226
- summary += f"\n✅ Authenticated using environment variable CIV3283_access"
227
- elif hf_token:
228
- summary += f"\n✅ Authenticated using manual token input"
229
- else:
230
- summary += f"\n⚠️ No authentication token found (may not access private repositories)"
231
-
232
  return summary
233
  except Exception as e:
234
- return f"❌ Failed to get file list: {str(e)}"
235
 
236
  # 创建Gradio界面
237
  def create_interface():
@@ -239,41 +185,18 @@ def create_interface():
239
  gr.Markdown("# 🗃️ CIV3283 数据存储管理器")
240
  gr.Markdown("从 Hugging Face Space 的 data_branch 分支整理和下载学生数据")
241
 
242
- # 认证部分
243
- with gr.Row():
244
- with gr.Column(scale=3):
245
- hf_token = gr.Textbox(
246
- label="🔐 Hugging Face Token (可选)",
247
- placeholder="hf_xxxxxxxxxxxx",
248
- type="password",
249
- info="可选:手动输入token,留空将使用环境变量 CIV3283_access"
250
- )
251
- with gr.Column(scale=1):
252
- gr.Markdown(f"""
253
- **环境变量状态:**
254
- {'✅ CIV3283_access 已设置' if os.getenv('CIV3283_access') else '❌ CIV3283_access 未找到'}
255
- """)
256
-
257
-
258
  # 文件概览
259
  with gr.Row():
260
  file_summary = gr.Textbox(
261
  label="📊 文件概览",
262
- value="点击刷新按钮获取文件列表",
263
  interactive=False,
264
- max_lines=6
265
  )
266
  refresh_btn = gr.Button("🔄 刷新文件列表", variant="secondary")
267
 
268
- # 自动刷新一次(使用环境变量)
269
- demo.load(
270
- fn=lambda: get_file_summary(None),
271
- outputs=file_summary
272
- )
273
-
274
  refresh_btn.click(
275
  fn=get_file_summary,
276
- inputs=[hf_token],
277
  outputs=file_summary
278
  )
279
 
@@ -317,11 +240,6 @@ def create_interface():
317
  # 使用说明
318
  with gr.Accordion("📖 使用说明", open=False):
319
  gr.Markdown("""
320
- ### 认证说明
321
- - **环境变量优先**: 系统会自动使用环境变量 `CIV3283_access` 中的token
322
- - **手动覆盖**: 如果需要使用不同的token,可以在上方手动输入
323
- - **获取token**: 如果需要新token,访问 https://huggingface.co/settings/tokens
324
-
325
  ### 功能说明
326
  1. **文件类型选择**: 选择要导出的数据类型
327
  - 查询文件: 包含搜索信息和查询响应
@@ -341,19 +259,18 @@ def create_interface():
341
  - 时间戳格式: 2025-06-16 08:55:33
342
  - 导出的数据保持原始顺序,不进行时间排序
343
  - 每次处理会显示详细的文件统计信息
344
- - 如果无法访问仓库API,系统会尝试预设的文件名列表
345
  """)
346
 
347
  # 绑定处理函数
348
  process_btn.click(
349
  fn=process_and_download,
350
- inputs=[file_type, start_date, end_date, hf_token],
351
  outputs=[status_box, download_file, gr.State()]
352
  )
353
 
354
  return demo
355
 
356
- # Launch application
357
  if __name__ == "__main__":
358
  demo = create_interface()
359
  demo.launch(
 
12
  def __init__(self, token=None):
13
  self.repo_id = "CIV3283/Data_Storage"
14
  self.branch = "data_branch"
15
+ self.token = token
16
 
17
+ # 如果提供了token,进行认证
 
 
 
18
  if self.token:
19
  try:
20
  login(token=self.token)
21
+ print("✅ 认证成功")
22
  except Exception as e:
23
+ print(f"❌ 认证失败: {e}")
24
 
25
  self.api = HfApi(token=self.token)
26
 
27
  def get_available_files(self) -> Tuple[List[str], List[str]]:
28
+ """获取所有可用的feedback和query文件"""
29
  try:
30
+ # 获取仓库中的所有文件
31
  repo_files = self.api.list_repo_files(
32
  repo_id=self.repo_id,
33
+ revision=self.branch
 
 
34
  )
35
 
36
  feedback_files = []
 
45
  return sorted(feedback_files), sorted(query_files)
46
 
47
  except Exception as e:
48
+ print(f"Error getting files: {e}")
49
+ return [], []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  def download_and_read_csv(self, filename: str) -> pd.DataFrame:
52
+ """下载并读取CSV文件"""
53
  try:
54
+ # 下载文件到临时位置
55
  local_file = hf_hub_download(
56
  repo_id=self.repo_id,
57
  filename=filename,
58
  revision=self.branch,
 
 
59
  cache_dir=tempfile.gettempdir()
60
  )
61
 
62
+ # 读取CSV
63
  df = pd.read_csv(local_file)
64
 
65
+ # 确保timestamp列存在并转换为datetime
66
  if 'timestamp' in df.columns:
67
  df['timestamp'] = pd.to_datetime(df['timestamp'])
68
 
69
  return df
70
 
71
  except Exception as e:
72
+ print(f"Error reading {filename}: {e}")
 
73
  return pd.DataFrame()
74
 
75
  def filter_data_by_date(self, df: pd.DataFrame, start_date: str, end_date: str) -> pd.DataFrame:
76
+ """根据日期范围筛选数据"""
77
  if df.empty or 'timestamp' not in df.columns:
78
  return df
79
 
80
  try:
81
+ # 转换输入的日期字符串
82
  start_dt = pd.to_datetime(start_date)
83
 
84
+ if end_date == "现在":
85
  end_dt = pd.Timestamp.now()
86
  else:
87
+ end_dt = pd.to_datetime(end_date) + timedelta(days=1) - timedelta(seconds=1) # 包含整天
88
 
89
+ # 筛选数据
90
  mask = (df['timestamp'] >= start_dt) & (df['timestamp'] <= end_dt)
91
  return df[mask]
92
 
 
95
  return df
96
 
97
  def process_files(self, file_type: str, start_date: str, end_date: str) -> Tuple[str, str, str]:
98
+ """处理文件并生成下载内容"""
99
  feedback_files, query_files = self.get_available_files()
100
 
101
  result_data = []
102
  file_info = []
103
  total_records = 0
104
 
105
+ # 根据选择的文件类型确定要处理的文件
106
  files_to_process = []
107
+ if file_type in ["反馈文件", "两者都要"]:
108
  files_to_process.extend([(f, "feedback") for f in feedback_files])
109
+ if file_type in ["查询文件", "两者都要"]:
110
  files_to_process.extend([(f, "query") for f in query_files])
111
 
112
+ # 处理每个文件
113
  for filename, ftype in files_to_process:
114
  df = self.download_and_read_csv(filename)
115
  if not df.empty:
 
121
  result_data.append(filtered_df)
122
  total_records += filtered_count
123
 
124
+ file_info.append(f"{filename}: {original_count}条记录 → {filtered_count}条符合条件")
125
 
126
+ # 合并所有数据
127
  if result_data:
128
  combined_df = pd.concat(result_data, ignore_index=True)
129
 
130
+ # 生成CSV内容
131
  csv_buffer = io.StringIO()
132
  combined_df.to_csv(csv_buffer, index=False, encoding='utf-8')
133
  csv_content = csv_buffer.getvalue()
134
 
135
+ # 生成文件名
136
+ end_date_str = "现在" if end_date == "现在" else end_date
137
+ filename = f"CIV3283_数据导出_{file_type}_{start_date}_to_{end_date_str}.csv"
 
138
 
139
+ # 生成状态信息
140
+ status = f"✅ 成功处理 {len(files_to_process)} 个文件\n"
141
+ status += f"📊 总共找到 {total_records} 条符合条件的记录\n"
142
+ status += f"📅 时间范围: {start_date} 到 {end_date_str}\n\n"
143
+ status += "文件详情:\n" + "\n".join(file_info)
144
 
145
  return csv_content, filename, status
146
  else:
147
+ return "", "", "❌ 没有找到符合条件的数据"
 
 
 
148
 
149
+ # 初始化数据管理器
150
+ data_manager = DataManager()
 
 
 
151
 
152
+ def process_and_download(file_type, start_date, end_date):
153
+ """处理请求并返回下载文件"""
154
  try:
 
 
 
 
 
 
 
 
155
  csv_content, filename, status = data_manager.process_files(file_type, start_date, end_date)
156
 
157
  if csv_content:
158
+ # 创建临时文件
159
  temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False, encoding='utf-8')
160
  temp_file.write(csv_content)
161
  temp_file.close()
 
165
  return status, None, None
166
 
167
  except Exception as e:
168
+ return f"❌ 处理过程中出现错误: {str(e)}", None, None
169
 
170
+ def get_file_summary():
171
+ """获取文件概览"""
172
  try:
 
 
 
 
 
 
 
 
173
  feedback_files, query_files = data_manager.get_available_files()
174
+ summary = f"📁 当前可用文件:\n"
175
+ summary += f" 反馈文件: {len(feedback_files)} 个\n"
176
+ summary += f" 查询文件: {len(query_files)} 个\n"
177
+ summary += f" 总计: {len(feedback_files) + len(query_files)} 个文件"
 
 
 
 
 
 
 
 
178
  return summary
179
  except Exception as e:
180
+ return f"❌ 获取文件列表失败: {str(e)}"
181
 
182
  # 创建Gradio界面
183
  def create_interface():
 
185
  gr.Markdown("# 🗃️ CIV3283 数据存储管理器")
186
  gr.Markdown("从 Hugging Face Space 的 data_branch 分支整理和下载学生数据")
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  # 文件概览
189
  with gr.Row():
190
  file_summary = gr.Textbox(
191
  label="📊 文件概览",
192
+ value=get_file_summary(),
193
  interactive=False,
194
+ max_lines=5
195
  )
196
  refresh_btn = gr.Button("🔄 刷新文件列表", variant="secondary")
197
 
 
 
 
 
 
 
198
  refresh_btn.click(
199
  fn=get_file_summary,
 
200
  outputs=file_summary
201
  )
202
 
 
240
  # 使用说明
241
  with gr.Accordion("📖 使用说明", open=False):
242
  gr.Markdown("""
 
 
 
 
 
243
  ### 功能说明
244
  1. **文件类型选择**: 选择要导出的数据类型
245
  - 查询文件: 包含搜索信息和查询响应
 
259
  - 时间戳格式: 2025-06-16 08:55:33
260
  - 导出的数据保持原始顺序,不进行时间排序
261
  - 每次处理会显示详细的文件统计信息
 
262
  """)
263
 
264
  # 绑定处理函数
265
  process_btn.click(
266
  fn=process_and_download,
267
+ inputs=[file_type, start_date, end_date],
268
  outputs=[status_box, download_file, gr.State()]
269
  )
270
 
271
  return demo
272
 
273
+ # 启动应用
274
  if __name__ == "__main__":
275
  demo = create_interface()
276
  demo.launch(