Factor Studios commited on
Commit
bec355c
·
verified ·
1 Parent(s): 2ae0b5a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +265 -4
app.py CHANGED
@@ -1,7 +1,268 @@
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- def greet(name):
4
- return "Hello " + name + "!!"
5
 
6
- demo = gr.Interface(fn=greet, inputs="text", outputs="text")
7
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import os
3
+ import json
4
+ import time
5
+ import threading
6
+ from fastapi import FastAPI, HTTPException, BackgroundTasks
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.responses import JSONResponse, FileResponse
9
+ import uvicorn
10
+ from typing import Dict
11
+ from pathlib import Path
12
+ import subprocess
13
+ from datetime import datetime
14
 
15
+ import torch
 
16
 
17
+
18
+ # Import from vision_analyzer (previously cursor_tracker)
19
+ from vision_analyzer import (
20
+ main_processing_loop,
21
+ processing_status,
22
+ ANALYSIS_OUTPUT_FOLDER, # Changed from CURSOR_TRACKING_OUTPUT_FOLDER
23
+ log_message
24
+ )
25
+
26
+ # FastAPI App Definition
27
+ app = FastAPI(title="Video Analysis API",
28
+ description="API to access video frame analysis results",
29
+ version="1.0.0")
30
+
31
+ # Add CORS middleware to allow cross-origin requests
32
+ app.add_middleware(
33
+ CORSMiddleware,
34
+ allow_origins=["*"], # Allows all origins
35
+ allow_credentials=True,
36
+ allow_methods=["*"], # Allows all methods
37
+ allow_headers=["*"],
38
+ )
39
+
40
+ # Global variable to track if processing is running
41
+ processing_thread = None
42
+
43
+ def log_message(message):
44
+ """Add a log message with timestamp"""
45
+ timestamp = datetime.now().strftime("%H:%M:%S")
46
+ log_entry = f"[{timestamp}] {message}"
47
+ processing_status["logs"].append(log_entry)
48
+
49
+ # Keep only the last 100 logs
50
+ if len(processing_status["logs"]) > 100:
51
+ processing_status["logs"] = processing_status["logs"][-100:]
52
+
53
+ print(log_entry)
54
+
55
+ @app.on_event("startup")
56
+ async def startup_event():
57
+ """Run the processing loop in the background when the API starts"""
58
+ global processing_thread
59
+ if not (processing_thread and processing_thread.is_alive()):
60
+ log_message("🚀 Starting RAR extraction, frame extraction, and vision analysis pipeline in background...")
61
+ processing_thread = threading.Thread(target=main_processing_loop)
62
+ processing_thread.daemon = True
63
+ processing_thread.start()
64
+
65
+ @app.get("/")
66
+ async def root():
67
+ """Root endpoint that returns basic info"""
68
+ return {
69
+ "message": "Video Analysis API",
70
+ "status": "running",
71
+ "endpoints": {
72
+ "/status": "Get processing status",
73
+ "/analysis-data": "List available analysis files",
74
+ "/analysis-data/{filename}": "Get specific analysis data",
75
+ "/start-processing": "Start processing pipeline",
76
+ "/stop-processing": "Stop processing pipeline"
77
+ }
78
+ }
79
+
80
+ @app.get("/status")
81
+ async def get_status():
82
+ """Get current processing status"""
83
+ return {
84
+ "processing_status": processing_status,
85
+ "analysis_folder": ANALYSIS_OUTPUT_FOLDER,
86
+ "folder_exists": os.path.exists(ANALYSIS_OUTPUT_FOLDER)
87
+ }
88
+
89
+ @app.get("/analysis-data")
90
+ async def list_analysis_data():
91
+ """List all available analysis JSON files"""
92
+ if not os.path.exists(ANALYSIS_OUTPUT_FOLDER):
93
+ return {"files": [], "message": "Analysis output folder does not exist yet"}
94
+
95
+ json_files = []
96
+ for file in os.listdir(ANALYSIS_OUTPUT_FOLDER):
97
+ if file.endswith(".json"):
98
+ file_path = os.path.join(ANALYSIS_OUTPUT_FOLDER, file)
99
+ file_stats = os.stat(file_path)
100
+ json_files.append({
101
+ "filename": file,
102
+ "size_bytes": file_stats.st_size,
103
+ "modified_time": time.ctime(file_stats.st_mtime),
104
+ "download_url": f"/analysis-data/{file}"
105
+ })
106
+
107
+ return {
108
+ "files": json_files,
109
+ "total_files": len(json_files),
110
+ "folder_path": ANALYSIS_OUTPUT_FOLDER
111
+ }
112
+
113
+ @app.get("/analysis-data/{filename}")
114
+ async def get_analysis_data(filename: str):
115
+ """Get specific analysis data by filename"""
116
+ if not filename.endswith(".json"):
117
+ raise HTTPException(status_code=400, detail="File must be a JSON file")
118
+
119
+ file_path = os.path.join(ANALYSIS_OUTPUT_FOLDER, filename)
120
+
121
+ if not os.path.exists(file_path):
122
+ raise HTTPException(status_code=404, detail=f"File {filename} not found")
123
+
124
+ try:
125
+ with open(file_path, "r") as f:
126
+ data = json.load(f)
127
+
128
+ # Add metadata
129
+ file_stats = os.stat(file_path)
130
+
131
+ # Extract summary information
132
+ frame_analyses = data.get("frame_analyses", [])
133
+ summary = data.get("summary", {})
134
+
135
+ response_data = {
136
+ "filename": filename,
137
+ "file_size_bytes": file_stats.st_size,
138
+ "modified_time": time.ctime(file_stats.st_mtime),
139
+ "total_frames": len(frame_analyses),
140
+ "summary": summary,
141
+ "frame_samples": frame_analyses[:5] # Return first 5 frames as samples
142
+ }
143
+
144
+ return response_data
145
+
146
+ except json.JSONDecodeError:
147
+ raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filename}")
148
+ except Exception as e:
149
+ raise HTTPException(status_code=500, detail=f"Error reading file {filename}: {str(e)}")
150
+
151
+ @app.get("/analysis-data/{filename}/full")
152
+ async def get_full_analysis_data(filename: str):
153
+ """Get the complete analysis data including all frames"""
154
+ if not filename.endswith(".json"):
155
+ raise HTTPException(status_code=400, detail="File must be a JSON file")
156
+
157
+ file_path = os.path.join(ANALYSIS_OUTPUT_FOLDER, filename)
158
+
159
+ if not os.path.exists(file_path):
160
+ raise HTTPException(status_code=404, detail=f"File {filename} not found")
161
+
162
+ try:
163
+ with open(file_path, "r") as f:
164
+ data = json.load(f)
165
+
166
+ # Add metadata
167
+ file_stats = os.stat(file_path)
168
+ data["metadata"] = {
169
+ "filename": filename,
170
+ "file_size_bytes": file_stats.st_size,
171
+ "modified_time": time.ctime(file_stats.st_mtime)
172
+ }
173
+
174
+ return data
175
+
176
+ except json.JSONDecodeError:
177
+ raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filename}")
178
+ except Exception as e:
179
+ raise HTTPException(status_code=500, detail=f"Error reading file {filename}: {str(e)}")
180
+
181
+ @app.post("/start-processing")
182
+ async def start_processing(background_tasks: BackgroundTasks, start_index: int = 0):
183
+ """Start the processing pipeline in the background"""
184
+ global processing_thread
185
+
186
+ if processing_thread and processing_thread.is_alive():
187
+ return {"message": "Processing is already running", "status": "already_running"}
188
+
189
+ if processing_status["is_running"]:
190
+ return {"message": "Processing is already running", "status": "already_running"}
191
+
192
+ # Start processing in a background thread
193
+ processing_thread = threading.Thread(target=main_processing_loop, args=(start_index,))
194
+ processing_thread.daemon = True
195
+ processing_thread.start()
196
+
197
+ return {"message": f"Processing started in background from index {start_index}", "status": "started"}
198
+
199
+ @app.post("/stop-processing")
200
+ async def stop_processing():
201
+ """Stop the processing pipeline"""
202
+ global processing_thread
203
+
204
+ if not processing_status["is_running"] and (not processing_thread or not processing_thread.is_alive()):
205
+ return {"message": "No processing is currently running", "status": "not_running"}
206
+
207
+ # Note: This is a graceful stop request
208
+ processing_status["is_running"] = False
209
+
210
+ return {"message": "Stop signal sent to processing pipeline", "status": "stop_requested"}
211
+
212
+ @app.get("/analysis-data/{filename}/summary")
213
+ async def get_analysis_summary(filename: str):
214
+ """Get a summary of the analysis data"""
215
+ if not filename.endswith(".json"):
216
+ raise HTTPException(status_code=400, detail="File must be a JSON file")
217
+
218
+ file_path = os.path.join(ANALYSIS_OUTPUT_FOLDER, filename)
219
+
220
+ if not os.path.exists(file_path):
221
+ raise HTTPException(status_code=404, detail=f"File {filename} not found")
222
+
223
+ try:
224
+ with open(file_path, "r") as f:
225
+ data = json.load(f)
226
+
227
+ # Get basic statistics
228
+ frame_analyses = data.get("frame_analyses", [])
229
+ summary = data.get("summary", {})
230
+
231
+ # Count frames with descriptions
232
+ frames_with_descriptions = len([f for f in frame_analyses if f.get("description")])
233
+
234
+ file_stats = os.stat(file_path)
235
+
236
+ return {
237
+ "filename": filename,
238
+ "file_size_bytes": file_stats.st_size,
239
+ "modified_time": time.ctime(file_stats.st_mtime),
240
+ "total_frames": len(frame_analyses),
241
+ "frames_with_descriptions": frames_with_descriptions,
242
+ "summary": summary,
243
+ "steps": summary.get("steps", []),
244
+ "high_level_goal": summary.get("high_level_goal", ""),
245
+ "final_goal": summary.get("final_goal", "")
246
+ }
247
+
248
+ except json.JSONDecodeError:
249
+ raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filename}")
250
+ except Exception as e:
251
+ raise HTTPException(status_code=500, detail=f"Error reading file {filename}: {str(e)}")
252
+
253
+ if __name__ == "__main__":
254
+ # Start the FastAPI server
255
+ print("Starting Video Analysis FastAPI Server...")
256
+ print("API Documentation will be available at: http://localhost:8000/docs")
257
+ print("API Root endpoint: http://localhost:8000/")
258
+
259
+ # Ensure the analysis output folder exists
260
+ os.makedirs(ANALYSIS_OUTPUT_FOLDER, exist_ok=True)
261
+
262
+ uvicorn.run(
263
+ app,
264
+ host="0.0.0.0",
265
+ port=8000,
266
+ log_level="info",
267
+ reload=False # Set to False for production
268
+ )