basyx commited on
Commit
5ed7b3d
·
verified ·
1 Parent(s): a92714d

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +32 -76
main.py CHANGED
@@ -44,6 +44,15 @@ from publisher.bulk import execute as bulk_execute
44
  from publisher.metadata_engine import generate_metadata
45
  from publisher.thumbnail_engine import generate_thumbnail
46
 
 
 
 
 
 
 
 
 
 
47
  # ==============================
48
  # INIT
49
  # ==============================
@@ -52,22 +61,25 @@ os.makedirs(UPLOAD_DIR, exist_ok=True)
52
 
53
 
54
  # ==============================
55
- # LIFECYCLE (FIXED)
56
  # ==============================
57
  @asynccontextmanager
58
  async def lifespan(app: FastAPI):
59
-
60
  logger.info("Starting Basyx Whisper V10.1")
61
 
62
- # DB init (AUTH)
63
- Base.metadata.create_all(bind=engine)
 
 
 
64
 
65
- # workers
66
  start_worker()
67
  init_scheduler()
68
 
69
- # autonomous engine
70
- asyncio.create_task(autonomous_loop())
 
 
71
 
72
  yield
73
 
@@ -79,10 +91,8 @@ app = FastAPI(
79
  lifespan=lifespan,
80
  )
81
 
82
- # AUTH ROUTES
83
  app.include_router(auth_router)
84
 
85
-
86
  # ==============================
87
  # TASK REGISTRY
88
  # ==============================
@@ -113,19 +123,19 @@ def normalize_task(task: str):
113
 
114
 
115
  # ==============================
116
- # SAFE INPUT RESOLVER (FIXED CRASH)
117
  # ==============================
118
  async def safe_resolve(file, source):
119
-
120
  try:
121
  if not file and not source:
122
  return None
123
 
124
- # 🔴 FIX: resolve_input expects UploadFile OR path, not raw string confusion
 
125
  return await asyncio.to_thread(
126
  resolve_input,
127
  source,
128
- file if isinstance(file, UploadFile) else None,
129
  )
130
 
131
  except Exception as e:
@@ -141,57 +151,34 @@ async def execute_task(video_path, task, payload=None, webhook=None):
141
  payload = payload or {}
142
  logger.info(f"[TASK] {task}")
143
 
144
- # -------- BULK ----------
145
  if task == "bulk-publish":
146
  return await bulk_execute(payload), None
147
 
148
- # -------- INPUT GUARD ----------
149
  if task not in ["bulk-publish", "schedule-post"] and not video_path:
150
  return {"error": "No valid input resolved"}, None
151
 
152
- # -------- AUTONOMOUS ----------
153
  if task == "autonomous":
154
- result = await asyncio.to_thread(run_autonomous_engine, video_path)
155
- return result, None
156
 
157
  if task == "auto-publish":
158
  auto = await asyncio.to_thread(run_autonomous_engine, video_path)
159
- return await dispatch_publish(
160
- variants=auto.get("all_variants", [])
161
- ), None
162
 
163
- # -------- PUBLISH ----------
164
  if task == "publish":
165
- return await dispatch_publish(
166
- video_path=video_path,
167
- payload=payload,
168
- ), None
169
 
170
- # -------- METADATA ----------
171
  if task == "generate-metadata":
172
  return generate_metadata(video_path), None
173
 
174
- # -------- THUMBNAIL ----------
175
  if task == "generate-thumbnail":
176
-
177
- output_path = os.path.join(
178
- UPLOAD_DIR,
179
- f"{uuid.uuid4()}.jpg"
180
- )
181
-
182
- thumb = generate_thumbnail(
183
- video_path,
184
- output=output_path,
185
- )
186
-
187
  return {"thumbnail": thumb}, output_path
188
 
189
- # -------- QUEUE ----------
190
  if task == "batch":
191
  job_id = create_job(video_path, webhook=webhook)
192
  return {"status": "queued", "job_id": job_id}, None
193
 
194
- # -------- TRANSCRIBE ----------
195
  if task == "transcribe":
196
  words = await asyncio.to_thread(transcribe_video, video_path)
197
  return {"words": words}, None
@@ -200,56 +187,34 @@ async def execute_task(video_path, task, payload=None, webhook=None):
200
  words = await asyncio.to_thread(transcribe_video, video_path)
201
  return {"srt": generate_srt(words)}, None
202
 
203
- # -------- RENDER ----------
204
  if task == "render":
205
-
206
  words = await asyncio.to_thread(transcribe_video, video_path)
207
  srt = generate_srt(words)
208
 
209
- output = os.path.join(
210
- UPLOAD_DIR,
211
- f"{uuid.uuid4()}_render.mp4",
212
- )
213
 
214
- await asyncio.to_thread(
215
- render_subtitles,
216
- video_path,
217
- srt,
218
- output,
219
- )
220
 
221
  return {"status": "render_complete"}, output
222
 
223
- # -------- HIGHLIGHTS ----------
224
  if task == "highlights":
225
-
226
  words = await asyncio.to_thread(transcribe_video, video_path)
227
  highlights = detect_highlights(words) or []
228
-
229
  clips = create_clips(video_path, highlights)
230
 
231
  return {"clips_created": len(clips)}, (clips[0] if clips else None)
232
 
233
  if task == "clips":
234
-
235
  words = await asyncio.to_thread(transcribe_video, video_path)
236
  highlights = detect_highlights(words) or []
237
-
238
  return {"clips": create_clips(video_path, highlights)}, None
239
 
240
- # -------- VIRAL SCORE ----------
241
  if task == "viral-score":
242
-
243
  words = await asyncio.to_thread(transcribe_video, video_path)
244
  segments = detect_highlights(words) or []
 
245
 
246
- return {
247
- "scores": [score_clip(s) for s in segments]
248
- }, None
249
-
250
- # -------- STRATEGY ----------
251
  if task == "strategy":
252
-
253
  words = await asyncio.to_thread(transcribe_video, video_path)
254
 
255
  script = rewrite_script(words)
@@ -283,9 +248,7 @@ async def execute_router(
283
  ):
284
 
285
  try:
286
-
287
  task = normalize_task(task_name)
288
-
289
  payload = {}
290
 
291
  if request.headers.get("content-type", "").startswith("application/json"):
@@ -293,12 +256,7 @@ async def execute_router(
293
 
294
  video_path = await safe_resolve(file, url_input or source)
295
 
296
- result, output = await execute_task(
297
- video_path,
298
- task,
299
- payload,
300
- webhook,
301
- )
302
 
303
  if output and isinstance(output, str) and os.path.exists(output):
304
  return FileResponse(output)
@@ -329,7 +287,6 @@ def status(job_id: str):
329
  async def ui_handler(video, task, webhook, url_input):
330
 
331
  source = url_input or video
332
-
333
  video_path = await safe_resolve(video, source)
334
 
335
  result, output = await execute_task(
@@ -343,7 +300,6 @@ async def ui_handler(video, task, webhook, url_input):
343
 
344
 
345
  with gr.Blocks() as demo:
346
-
347
  gr.Markdown("# 🚀 Basyx Whisper V10.1 Stable Operator")
348
 
349
  video_input = gr.Video()
 
44
  from publisher.metadata_engine import generate_metadata
45
  from publisher.thumbnail_engine import generate_thumbnail
46
 
47
+ # ==============================
48
+ # SAFETY PATCH: bcrypt/passlib crash shield
49
+ # ==============================
50
+ import passlib
51
+ try:
52
+ import bcrypt # noqa
53
+ except Exception as e:
54
+ logger.warning(f"bcrypt import issue detected (ignored at runtime startup): {e}")
55
+
56
  # ==============================
57
  # INIT
58
  # ==============================
 
61
 
62
 
63
  # ==============================
64
+ # LIFECYCLE (HARDENED)
65
  # ==============================
66
  @asynccontextmanager
67
  async def lifespan(app: FastAPI):
 
68
  logger.info("Starting Basyx Whisper V10.1")
69
 
70
+ try:
71
+ Base.metadata.create_all(bind=engine)
72
+ except Exception as e:
73
+ logger.error(f"DB init failed: {e}")
74
+ raise
75
 
 
76
  start_worker()
77
  init_scheduler()
78
 
79
+ try:
80
+ asyncio.create_task(autonomous_loop())
81
+ except Exception as e:
82
+ logger.error(f"autonomous_loop failed to start: {e}")
83
 
84
  yield
85
 
 
91
  lifespan=lifespan,
92
  )
93
 
 
94
  app.include_router(auth_router)
95
 
 
96
  # ==============================
97
  # TASK REGISTRY
98
  # ==============================
 
123
 
124
 
125
  # ==============================
126
+ # SAFE INPUT RESOLVER (FIXED)
127
  # ==============================
128
  async def safe_resolve(file, source):
 
129
  try:
130
  if not file and not source:
131
  return None
132
 
133
+ upload_file = file if isinstance(file, UploadFile) else None
134
+
135
  return await asyncio.to_thread(
136
  resolve_input,
137
  source,
138
+ upload_file,
139
  )
140
 
141
  except Exception as e:
 
151
  payload = payload or {}
152
  logger.info(f"[TASK] {task}")
153
 
 
154
  if task == "bulk-publish":
155
  return await bulk_execute(payload), None
156
 
 
157
  if task not in ["bulk-publish", "schedule-post"] and not video_path:
158
  return {"error": "No valid input resolved"}, None
159
 
 
160
  if task == "autonomous":
161
+ return await asyncio.to_thread(run_autonomous_engine, video_path), None
 
162
 
163
  if task == "auto-publish":
164
  auto = await asyncio.to_thread(run_autonomous_engine, video_path)
165
+ return await dispatch_publish(variants=auto.get("all_variants", [])), None
 
 
166
 
 
167
  if task == "publish":
168
+ return await dispatch_publish(video_path=video_path, payload=payload), None
 
 
 
169
 
 
170
  if task == "generate-metadata":
171
  return generate_metadata(video_path), None
172
 
 
173
  if task == "generate-thumbnail":
174
+ output_path = os.path.join(UPLOAD_DIR, f"{uuid.uuid4()}.jpg")
175
+ thumb = generate_thumbnail(video_path, output=output_path)
 
 
 
 
 
 
 
 
 
176
  return {"thumbnail": thumb}, output_path
177
 
 
178
  if task == "batch":
179
  job_id = create_job(video_path, webhook=webhook)
180
  return {"status": "queued", "job_id": job_id}, None
181
 
 
182
  if task == "transcribe":
183
  words = await asyncio.to_thread(transcribe_video, video_path)
184
  return {"words": words}, None
 
187
  words = await asyncio.to_thread(transcribe_video, video_path)
188
  return {"srt": generate_srt(words)}, None
189
 
 
190
  if task == "render":
 
191
  words = await asyncio.to_thread(transcribe_video, video_path)
192
  srt = generate_srt(words)
193
 
194
+ output = os.path.join(UPLOAD_DIR, f"{uuid.uuid4()}_render.mp4")
 
 
 
195
 
196
+ await asyncio.to_thread(render_subtitles, video_path, srt, output)
 
 
 
 
 
197
 
198
  return {"status": "render_complete"}, output
199
 
 
200
  if task == "highlights":
 
201
  words = await asyncio.to_thread(transcribe_video, video_path)
202
  highlights = detect_highlights(words) or []
 
203
  clips = create_clips(video_path, highlights)
204
 
205
  return {"clips_created": len(clips)}, (clips[0] if clips else None)
206
 
207
  if task == "clips":
 
208
  words = await asyncio.to_thread(transcribe_video, video_path)
209
  highlights = detect_highlights(words) or []
 
210
  return {"clips": create_clips(video_path, highlights)}, None
211
 
 
212
  if task == "viral-score":
 
213
  words = await asyncio.to_thread(transcribe_video, video_path)
214
  segments = detect_highlights(words) or []
215
+ return {"scores": [score_clip(s) for s in segments]}, None
216
 
 
 
 
 
 
217
  if task == "strategy":
 
218
  words = await asyncio.to_thread(transcribe_video, video_path)
219
 
220
  script = rewrite_script(words)
 
248
  ):
249
 
250
  try:
 
251
  task = normalize_task(task_name)
 
252
  payload = {}
253
 
254
  if request.headers.get("content-type", "").startswith("application/json"):
 
256
 
257
  video_path = await safe_resolve(file, url_input or source)
258
 
259
+ result, output = await execute_task(video_path, task, payload, webhook)
 
 
 
 
 
260
 
261
  if output and isinstance(output, str) and os.path.exists(output):
262
  return FileResponse(output)
 
287
  async def ui_handler(video, task, webhook, url_input):
288
 
289
  source = url_input or video
 
290
  video_path = await safe_resolve(video, source)
291
 
292
  result, output = await execute_task(
 
300
 
301
 
302
  with gr.Blocks() as demo:
 
303
  gr.Markdown("# 🚀 Basyx Whisper V10.1 Stable Operator")
304
 
305
  video_input = gr.Video()