Fred808 commited on
Commit
ae2f7ce
·
verified ·
1 Parent(s): 9e96cea

Update download_api.py

Browse files
Files changed (1) hide show
  1. download_api.py +90 -24
download_api.py CHANGED
@@ -31,6 +31,18 @@ app.add_middleware(
31
  # Global variable to track if processing is running
32
  processing_thread = None
33
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  @app.on_event("startup")
35
  async def startup_event():
36
  """Run the processing loop in the background when the API starts"""
@@ -44,17 +56,20 @@ async def startup_event():
44
  @app.get("/")
45
  async def root():
46
  """Root endpoint with API information"""
47
- return {
48
- "message": "Cursor Tracking API",
49
- "version": "1.0.0",
50
- "endpoints": {
51
- "/status": "Get processing status",
52
- "/cursor-data": "List all cursor tracking JSON files",
53
- "/cursor-data/{filename}": "Get specific cursor tracking data",
54
- "/start-processing": "Start the RAR processing pipeline",
55
- "/stop-processing": "Stop the RAR processing pipeline"
56
- }
57
- }
 
 
 
58
 
59
  @app.get("/status")
60
  async def get_status():
@@ -89,6 +104,20 @@ async def list_cursor_data():
89
  "folder_path": CURSOR_TRACKING_OUTPUT_FOLDER
90
  }
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  @app.get("/cursor-data/{filename}")
93
  async def get_cursor_data(filename: str):
94
  """Get specific cursor tracking data by filename"""
@@ -104,18 +133,34 @@ async def get_cursor_data(filename: str):
104
  with open(file_path, "r") as f:
105
  data = json.load(f)
106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  # Add metadata
108
  file_stats = os.stat(file_path)
109
  response_data = {
110
  "filename": filename,
111
  "file_size_bytes": file_stats.st_size,
112
  "modified_time": time.ctime(file_stats.st_mtime),
113
- "total_frames": len(data),
114
- "cursor_active_frames": len([frame for frame in data if frame.get("cursor_active", False)]),
115
- "data": data
116
  }
117
 
118
- return response_data
119
 
120
  except json.JSONDecodeError:
121
  raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filename}")
@@ -123,7 +168,7 @@ async def get_cursor_data(filename: str):
123
  raise HTTPException(status_code=500, detail=f"Error reading file {filename}: {str(e)}")
124
 
125
  @app.post("/start-processing")
126
- async def start_processing(background_tasks: BackgroundTasks):
127
  """Start the RAR processing pipeline in the background"""
128
  global processing_thread
129
 
@@ -134,11 +179,11 @@ async def start_processing(background_tasks: BackgroundTasks):
134
  return {"message": "Processing is already running", "status": "already_running"}
135
 
136
  # Start processing in a background thread
137
- processing_thread = threading.Thread(target=main_processing_loop)
138
  processing_thread.daemon = True
139
  processing_thread.start()
140
 
141
- return {"message": "Processing started in background", "status": "started"}
142
 
143
  @app.post("/stop-processing")
144
  async def stop_processing():
@@ -169,20 +214,42 @@ async def get_cursor_data_summary(filename: str):
169
  with open(file_path, "r") as f:
170
  data = json.load(f)
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  # Calculate summary statistics
173
- total_frames = len(data)
174
- cursor_active_frames = len([frame for frame in data if frame.get("cursor_active", False)])
175
  cursor_inactive_frames = total_frames - cursor_active_frames
176
 
177
  # Get unique templates used
178
  templates_used = set()
179
  confidence_scores = []
180
 
181
- for frame in data:
182
  if frame.get("cursor_active", False) and frame.get("template"):
183
  templates_used.add(frame["template"])
184
  if frame.get("confidence") is not None:
185
- confidence_scores.append(frame["confidence"])
 
 
 
 
 
 
186
 
187
  # Calculate confidence statistics
188
  avg_confidence = sum(confidence_scores) / len(confidence_scores) if confidence_scores else 0
@@ -208,7 +275,7 @@ async def get_cursor_data_summary(filename: str):
208
  }
209
  }
210
 
211
- return summary
212
 
213
  except json.JSONDecodeError:
214
  raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filename}")
@@ -233,4 +300,3 @@ if __name__ == "__main__":
233
  )
234
 
235
 
236
-
 
31
  # Global variable to track if processing is running
32
  processing_thread = None
33
 
34
+ def log_message(message):
35
+ """Add a log message with timestamp"""
36
+ timestamp = datetime.now().strftime("%H:%M:%S")
37
+ log_entry = f"[{timestamp}] {message}"
38
+ processing_status["logs"].append(log_entry)
39
+
40
+ # Keep only the last 100 logs
41
+ if len(processing_status["logs"]) > 100:
42
+ processing_status["logs"] = processing_status["logs"][-100:]
43
+
44
+ print(log_entry)
45
+
46
  @app.on_event("startup")
47
  async def startup_event():
48
  """Run the processing loop in the background when the API starts"""
 
56
  @app.get("/")
57
  async def root():
58
  """Root endpoint with API information"""
59
+ return send_file(os.path.join(BASE_DIR, 'index.html'))
60
+
61
+
62
+ @app.route('/<path:filename>')
63
+ def serve_static(filename):
64
+ """Serve static files (CSS, JS, etc.)"""
65
+ if filename in ['style.css', 'script.js']:
66
+ return send_from_directory(BASE_DIR, filename)
67
+ return send_from_directory(BASE_DIR, filename)
68
+
69
+ @app.route('/status')
70
+ def get_status():
71
+ """Get current processing status"""
72
+ return jsonify({"processing_status": processing_status})
73
 
74
  @app.get("/status")
75
  async def get_status():
 
104
  "folder_path": CURSOR_TRACKING_OUTPUT_FOLDER
105
  }
106
 
107
+ from fastapi.encoders import jsonable_encoder
108
+
109
+ class SafeJSONEncoder(json.JSONEncoder):
110
+ def default(self, obj):
111
+ try:
112
+ if isinstance(obj, float):
113
+ if obj != obj: # Check for NaN
114
+ return None
115
+ if obj == float('inf') or obj == float('-inf'):
116
+ return None
117
+ return super().default(obj)
118
+ except:
119
+ return None
120
+
121
  @app.get("/cursor-data/{filename}")
122
  async def get_cursor_data(filename: str):
123
  """Get specific cursor tracking data by filename"""
 
133
  with open(file_path, "r") as f:
134
  data = json.load(f)
135
 
136
+ # Clean the data of any NaN or infinity values
137
+ def clean_floats(obj):
138
+ if isinstance(obj, float):
139
+ if obj != obj: # NaN
140
+ return None
141
+ if obj == float('inf') or obj == float('-inf'):
142
+ return None
143
+ return obj
144
+ elif isinstance(obj, dict):
145
+ return {k: clean_floats(v) for k, v in obj.items()}
146
+ elif isinstance(obj, list):
147
+ return [clean_floats(v) for v in obj]
148
+ return obj
149
+
150
+ cleaned_data = clean_floats(data)
151
+
152
  # Add metadata
153
  file_stats = os.stat(file_path)
154
  response_data = {
155
  "filename": filename,
156
  "file_size_bytes": file_stats.st_size,
157
  "modified_time": time.ctime(file_stats.st_mtime),
158
+ "total_frames": len(cleaned_data),
159
+ "cursor_active_frames": len([frame for frame in cleaned_data if frame.get("cursor_active", False)]),
160
+ "data": cleaned_data
161
  }
162
 
163
+ return JSONResponse(content=jsonable_encoder(response_data))
164
 
165
  except json.JSONDecodeError:
166
  raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filename}")
 
168
  raise HTTPException(status_code=500, detail=f"Error reading file {filename}: {str(e)}")
169
 
170
  @app.post("/start-processing")
171
+ async def start_processing(background_tasks: BackgroundTasks, start_index: int = 0):
172
  """Start the RAR processing pipeline in the background"""
173
  global processing_thread
174
 
 
179
  return {"message": "Processing is already running", "status": "already_running"}
180
 
181
  # Start processing in a background thread
182
+ processing_thread = threading.Thread(target=main_processing_loop, args=(start_index,))
183
  processing_thread.daemon = True
184
  processing_thread.start()
185
 
186
+ return {"message": f"Processing started in background from index {start_index}", "status": "started"}
187
 
188
  @app.post("/stop-processing")
189
  async def stop_processing():
 
214
  with open(file_path, "r") as f:
215
  data = json.load(f)
216
 
217
+ # Clean the data first
218
+ def clean_floats(obj):
219
+ if isinstance(obj, float):
220
+ if obj != obj: # NaN
221
+ return None
222
+ if obj == float('inf') or obj == float('-inf'):
223
+ return None
224
+ return obj
225
+ elif isinstance(obj, dict):
226
+ return {k: clean_floats(v) for k, v in obj.items()}
227
+ elif isinstance(obj, list):
228
+ return [clean_floats(v) for v in obj]
229
+ return obj
230
+
231
+ cleaned_data = clean_floats(data)
232
+
233
  # Calculate summary statistics
234
+ total_frames = len(cleaned_data)
235
+ cursor_active_frames = len([frame for frame in cleaned_data if frame.get("cursor_active", False)])
236
  cursor_inactive_frames = total_frames - cursor_active_frames
237
 
238
  # Get unique templates used
239
  templates_used = set()
240
  confidence_scores = []
241
 
242
+ for frame in cleaned_data:
243
  if frame.get("cursor_active", False) and frame.get("template"):
244
  templates_used.add(frame["template"])
245
  if frame.get("confidence") is not None:
246
+ # Ensure confidence is a valid number
247
+ try:
248
+ conf = float(frame["confidence"])
249
+ if not (conf != conf or conf == float('inf') or conf == float('-inf')):
250
+ confidence_scores.append(conf)
251
+ except (ValueError, TypeError):
252
+ pass
253
 
254
  # Calculate confidence statistics
255
  avg_confidence = sum(confidence_scores) / len(confidence_scores) if confidence_scores else 0
 
275
  }
276
  }
277
 
278
+ return JSONResponse(content=jsonable_encoder(summary))
279
 
280
  except json.JSONDecodeError:
281
  raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filename}")
 
300
  )
301
 
302