Spaces:
Running
Running
v5.1: add auto-scheduler trigger endpoint + route protection, fix short gen
Browse files- ai_runtime_patch_fast.py +46 -2
ai_runtime_patch_fast.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
| 1 |
-
"""Final patch v5: SYNCHRONOUS short video generation, no silent errors, log everything."""
|
| 2 |
import re, threading, time, json, os, asyncio, hashlib, subprocess, requests, sys, logging
|
| 3 |
import ai_runtime_final6 as f6
|
| 4 |
from ai_runtime_final6 import app, rt, f5, HTMLResponse, JSONResponse, FileResponse, Request, Query
|
| 5 |
import html as html_lib
|
| 6 |
from urllib.parse import urlparse
|
|
|
|
| 7 |
|
| 8 |
_log = logging.getLogger("patch_fast")
|
| 9 |
_log.setLevel(logging.INFO)
|
|
@@ -234,6 +235,49 @@ def _gen_short_sync(post) -> str:
|
|
| 234 |
_log.error("No part files generated!")
|
| 235 |
return ''
|
| 236 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
_bg_home={"t":0,"d":[]};_bg_shorts={"t":0,"d":[]};_bg_lock=False
|
| 238 |
def _bg():
|
| 239 |
global _bg_lock
|
|
@@ -250,7 +294,7 @@ def _bg():
|
|
| 250 |
@app.on_event("startup")
|
| 251 |
async def _s():threading.Thread(target=_bg,daemon=True).start()
|
| 252 |
threading.Thread(target=lambda:[time.sleep(600) or _bg() for _ in iter(int,1)],daemon=True).start()
|
| 253 |
-
app.router.routes=[r for r in app.router.routes if not (getattr(r,'path',None) in ('/api/homepage','/api/shorts','/api/ai_wall','/api/topic_post','/api/article/ask','/api/topic/rewrite','/api/rewrite_share','/api/url_wall','/api/short/comments','/api/short/comment','/api/storage_status','/api/ai/short/{post_id}','/api/ai/short-file/{file_id}','/') and any(m in getattr(r,'methods',set()) for m in ('GET','POST')))]
|
| 254 |
@app.get('/api/homepage')
|
| 255 |
def _h():
|
| 256 |
n=time.time()
|
|
|
|
| 1 |
+
"""Final patch v5: SYNCHRONOUS short video generation, no silent errors, log everything. + Auto scheduler trigger."""
|
| 2 |
import re, threading, time, json, os, asyncio, hashlib, subprocess, requests, sys, logging
|
| 3 |
import ai_runtime_final6 as f6
|
| 4 |
from ai_runtime_final6 import app, rt, f5, HTMLResponse, JSONResponse, FileResponse, Request, Query
|
| 5 |
import html as html_lib
|
| 6 |
from urllib.parse import urlparse
|
| 7 |
+
from datetime import datetime, timezone, timedelta
|
| 8 |
|
| 9 |
_log = logging.getLogger("patch_fast")
|
| 10 |
_log.setLevel(logging.INFO)
|
|
|
|
| 235 |
_log.error("No part files generated!")
|
| 236 |
return ''
|
| 237 |
|
| 238 |
+
# ===== Auto Scheduler Trigger =====
|
| 239 |
+
_AUTO_SCHEDULER_RUNNING = False
|
| 240 |
+
_AUTO_SCHEDULER_LAST = 0
|
| 241 |
+
_AUTO_SCHEDULER_RESULTS = []
|
| 242 |
+
|
| 243 |
+
def _run_scheduler_now():
|
| 244 |
+
"""Trigger auto_scheduler._run_scheduled_posting() safely."""
|
| 245 |
+
global _AUTO_SCHEDULER_RUNNING, _AUTO_SCHEDULER_LAST, _AUTO_SCHEDULER_RESULTS
|
| 246 |
+
if _AUTO_SCHEDULER_RUNNING:
|
| 247 |
+
_log.warning("Scheduler already running!")
|
| 248 |
+
return {"status": "running", "message": "Scheduler đang chạy, vui lòng đợi."}
|
| 249 |
+
_AUTO_SCHEDULER_RUNNING = True
|
| 250 |
+
try:
|
| 251 |
+
import auto_scheduler as _as
|
| 252 |
+
_as.LOG.info("Triggered manually via API")
|
| 253 |
+
_as._run_scheduled_posting()
|
| 254 |
+
_AUTO_SCHEDULER_LAST = time.time()
|
| 255 |
+
_AUTO_SCHEDULER_RESULTS = [{'time': datetime.now().strftime('%H:%M %d/%m/%Y'), 'status': 'done'}]
|
| 256 |
+
_log.info("Auto scheduler completed successfully")
|
| 257 |
+
return {"status": "done", "message": "Đã đăng 3 bài tự động thành công!"}
|
| 258 |
+
except Exception as e:
|
| 259 |
+
_log.error(f"Auto scheduler failed: {e}", exc_info=True)
|
| 260 |
+
return {"status": "error", "message": f"Lỗi: {e}"}
|
| 261 |
+
finally:
|
| 262 |
+
_AUTO_SCHEDULER_RUNNING = False
|
| 263 |
+
|
| 264 |
+
@app.post('/api/auto/schedule')
|
| 265 |
+
async def _api_auto_schedule():
|
| 266 |
+
"""Trigger auto-scheduler to post 3 articles NOW."""
|
| 267 |
+
_log.info("POST /api/auto/schedule triggered")
|
| 268 |
+
result = await asyncio.get_event_loop().run_in_executor(None, _run_scheduler_now)
|
| 269 |
+
return JSONResponse(result)
|
| 270 |
+
|
| 271 |
+
@app.get('/api/auto/status')
|
| 272 |
+
async def _api_auto_status():
|
| 273 |
+
"""Check auto-scheduler status."""
|
| 274 |
+
return JSONResponse({
|
| 275 |
+
'running': _AUTO_SCHEDULER_RUNNING,
|
| 276 |
+
'last_run': _AUTO_SCHEDULER_LAST,
|
| 277 |
+
'last_run_str': datetime.fromtimestamp(_AUTO_SCHEDULER_LAST).strftime('%H:%M %d/%m/%Y') if _AUTO_SCHEDULER_LAST else 'never',
|
| 278 |
+
'results': _AUTO_SCHEDULER_RESULTS
|
| 279 |
+
})
|
| 280 |
+
|
| 281 |
_bg_home={"t":0,"d":[]};_bg_shorts={"t":0,"d":[]};_bg_lock=False
|
| 282 |
def _bg():
|
| 283 |
global _bg_lock
|
|
|
|
| 294 |
@app.on_event("startup")
|
| 295 |
async def _s():threading.Thread(target=_bg,daemon=True).start()
|
| 296 |
threading.Thread(target=lambda:[time.sleep(600) or _bg() for _ in iter(int,1)],daemon=True).start()
|
| 297 |
+
app.router.routes=[r for r in app.router.routes if not (getattr(r,'path',None) in ('/api/homepage','/api/shorts','/api/ai_wall','/api/topic_post','/api/article/ask','/api/topic/rewrite','/api/rewrite_share','/api/url_wall','/api/short/comments','/api/short/comment','/api/storage_status','/api/ai/short/{post_id}','/api/ai/short-file/{file_id}','/api/auto/schedule','/api/auto/status','/') and any(m in getattr(r,'methods',set()) for m in ('GET','POST')))]
|
| 298 |
@app.get('/api/homepage')
|
| 299 |
def _h():
|
| 300 |
n=time.time()
|