Spaces:
Running
Running
remove temp audio and video
Browse files
app.py
CHANGED
|
@@ -1526,117 +1526,6 @@ Generate complete, working HTML code that can be run immediately.
|
|
| 1526 |
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 1527 |
"""
|
| 1528 |
|
| 1529 |
-
# ---------------------------------------------------------------------------
|
| 1530 |
-
# Video temp-file management (per-session tracking and cleanup)
|
| 1531 |
-
# ---------------------------------------------------------------------------
|
| 1532 |
-
VIDEO_TEMP_DIR = os.path.join(tempfile.gettempdir(), "anycoder_videos")
|
| 1533 |
-
VIDEO_FILE_TTL_SECONDS = 6 * 60 * 60 # 6 hours
|
| 1534 |
-
_SESSION_VIDEO_FILES: Dict[str, List[str]] = {}
|
| 1535 |
-
_VIDEO_FILES_LOCK = threading.Lock()
|
| 1536 |
-
|
| 1537 |
-
|
| 1538 |
-
def _ensure_video_dir_exists() -> None:
|
| 1539 |
-
try:
|
| 1540 |
-
os.makedirs(VIDEO_TEMP_DIR, exist_ok=True)
|
| 1541 |
-
except Exception:
|
| 1542 |
-
pass
|
| 1543 |
-
def _register_video_for_session(session_id: str | None, file_path: str) -> None:
|
| 1544 |
-
if not session_id or not file_path:
|
| 1545 |
-
return
|
| 1546 |
-
with _VIDEO_FILES_LOCK:
|
| 1547 |
-
if session_id not in _SESSION_VIDEO_FILES:
|
| 1548 |
-
_SESSION_VIDEO_FILES[session_id] = []
|
| 1549 |
-
_SESSION_VIDEO_FILES[session_id].append(file_path)
|
| 1550 |
-
|
| 1551 |
-
|
| 1552 |
-
def cleanup_session_videos(session_id: str | None) -> None:
|
| 1553 |
-
if not session_id:
|
| 1554 |
-
return
|
| 1555 |
-
with _VIDEO_FILES_LOCK:
|
| 1556 |
-
file_list = _SESSION_VIDEO_FILES.pop(session_id, [])
|
| 1557 |
-
for path in file_list:
|
| 1558 |
-
try:
|
| 1559 |
-
if path and os.path.exists(path):
|
| 1560 |
-
os.unlink(path)
|
| 1561 |
-
except Exception:
|
| 1562 |
-
# Best-effort cleanup
|
| 1563 |
-
pass
|
| 1564 |
-
|
| 1565 |
-
|
| 1566 |
-
def reap_old_videos(ttl_seconds: int = VIDEO_FILE_TTL_SECONDS) -> None:
|
| 1567 |
-
"""Delete old video files in the temp directory based on modification time."""
|
| 1568 |
-
try:
|
| 1569 |
-
_ensure_video_dir_exists()
|
| 1570 |
-
now_ts = time.time()
|
| 1571 |
-
for name in os.listdir(VIDEO_TEMP_DIR):
|
| 1572 |
-
path = os.path.join(VIDEO_TEMP_DIR, name)
|
| 1573 |
-
try:
|
| 1574 |
-
if not os.path.isfile(path):
|
| 1575 |
-
continue
|
| 1576 |
-
mtime = os.path.getmtime(path)
|
| 1577 |
-
if now_ts - mtime > ttl_seconds:
|
| 1578 |
-
os.unlink(path)
|
| 1579 |
-
except Exception:
|
| 1580 |
-
pass
|
| 1581 |
-
except Exception:
|
| 1582 |
-
# Temp dir might not exist or be accessible; ignore
|
| 1583 |
-
pass
|
| 1584 |
-
|
| 1585 |
-
# ---------------------------------------------------------------------------
|
| 1586 |
-
# Audio temp-file management (per-session tracking and cleanup)
|
| 1587 |
-
# ---------------------------------------------------------------------------
|
| 1588 |
-
AUDIO_TEMP_DIR = os.path.join(tempfile.gettempdir(), "anycoder_audio")
|
| 1589 |
-
AUDIO_FILE_TTL_SECONDS = 6 * 60 * 60 # 6 hours
|
| 1590 |
-
_SESSION_AUDIO_FILES: Dict[str, List[str]] = {}
|
| 1591 |
-
_AUDIO_FILES_LOCK = threading.Lock()
|
| 1592 |
-
|
| 1593 |
-
|
| 1594 |
-
def _ensure_audio_dir_exists() -> None:
|
| 1595 |
-
try:
|
| 1596 |
-
os.makedirs(AUDIO_TEMP_DIR, exist_ok=True)
|
| 1597 |
-
except Exception:
|
| 1598 |
-
pass
|
| 1599 |
-
|
| 1600 |
-
|
| 1601 |
-
def _register_audio_for_session(session_id: str | None, file_path: str) -> None:
|
| 1602 |
-
if not session_id or not file_path:
|
| 1603 |
-
return
|
| 1604 |
-
with _AUDIO_FILES_LOCK:
|
| 1605 |
-
if session_id not in _SESSION_AUDIO_FILES:
|
| 1606 |
-
_SESSION_AUDIO_FILES[session_id] = []
|
| 1607 |
-
_SESSION_AUDIO_FILES[session_id].append(file_path)
|
| 1608 |
-
|
| 1609 |
-
|
| 1610 |
-
def cleanup_session_audio(session_id: str | None) -> None:
|
| 1611 |
-
if not session_id:
|
| 1612 |
-
return
|
| 1613 |
-
with _AUDIO_FILES_LOCK:
|
| 1614 |
-
file_list = _SESSION_AUDIO_FILES.pop(session_id, [])
|
| 1615 |
-
for path in file_list:
|
| 1616 |
-
try:
|
| 1617 |
-
if path and os.path.exists(path):
|
| 1618 |
-
os.unlink(path)
|
| 1619 |
-
except Exception:
|
| 1620 |
-
pass
|
| 1621 |
-
|
| 1622 |
-
|
| 1623 |
-
def reap_old_audio(ttl_seconds: int = AUDIO_FILE_TTL_SECONDS) -> None:
|
| 1624 |
-
try:
|
| 1625 |
-
_ensure_audio_dir_exists()
|
| 1626 |
-
now_ts = time.time()
|
| 1627 |
-
for name in os.listdir(AUDIO_TEMP_DIR):
|
| 1628 |
-
path = os.path.join(AUDIO_TEMP_DIR, name)
|
| 1629 |
-
try:
|
| 1630 |
-
if not os.path.isfile(path):
|
| 1631 |
-
continue
|
| 1632 |
-
mtime = os.path.getmtime(path)
|
| 1633 |
-
if now_ts - mtime > ttl_seconds:
|
| 1634 |
-
os.unlink(path)
|
| 1635 |
-
except Exception:
|
| 1636 |
-
pass
|
| 1637 |
-
except Exception:
|
| 1638 |
-
pass
|
| 1639 |
-
|
| 1640 |
TRANSFORMERS_JS_SYSTEM_PROMPT = """You are an expert web developer creating a transformers.js application. You will generate THREE separate files: index.html, index.js, and style.css.
|
| 1641 |
|
| 1642 |
**🚨 CRITICAL: DO NOT Generate README.md Files**
|
|
@@ -3557,7 +3446,7 @@ def apply_transformers_js_search_replace_changes(original_formatted_content: str
|
|
| 3557 |
def send_to_sandbox(code):
|
| 3558 |
"""Render HTML in a sandboxed iframe. Assumes full HTML is provided by prompts."""
|
| 3559 |
html_doc = (code or "").strip()
|
| 3560 |
-
# For preview only: inline local file URLs
|
| 3561 |
# data: iframe can load them. The original code (shown to the user) still contains file URLs.
|
| 3562 |
try:
|
| 3563 |
import re
|
|
@@ -3574,17 +3463,6 @@ def send_to_sandbox(code):
|
|
| 3574 |
raw = _f.read()
|
| 3575 |
mime = _mtypes.guess_type(path)[0] or 'application/octet-stream'
|
| 3576 |
|
| 3577 |
-
# Compress video files before converting to data URI to prevent preview breaks
|
| 3578 |
-
if mime and mime.startswith('video/'):
|
| 3579 |
-
print(f"[Sandbox] Compressing video for preview: {len(raw)} bytes")
|
| 3580 |
-
raw = compress_video_for_data_uri(raw, max_size_mb=1) # Very small limit for preview
|
| 3581 |
-
print(f"[Sandbox] Compressed video size: {len(raw)} bytes")
|
| 3582 |
-
|
| 3583 |
-
# If still too large, skip video embedding for preview
|
| 3584 |
-
if len(raw) > 512 * 1024: # 512KB final limit
|
| 3585 |
-
print(f"[Sandbox] Video still too large after compression, using placeholder")
|
| 3586 |
-
return None # Let the replacement function handle the fallback
|
| 3587 |
-
|
| 3588 |
b64 = _b64.b64encode(raw).decode()
|
| 3589 |
return f"data:{mime};base64,{b64}"
|
| 3590 |
except Exception as e:
|
|
@@ -3600,35 +3478,6 @@ def send_to_sandbox(code):
|
|
| 3600 |
return f"src='{data_uri}'" if data_uri else m.group(0)
|
| 3601 |
html_doc = re.sub(r'src="(file:[^"]+)"', _repl_double, html_doc)
|
| 3602 |
html_doc = re.sub(r"src='(file:[^']+)'", _repl_single, html_doc)
|
| 3603 |
-
|
| 3604 |
-
# Add deployment message for videos that couldn't be converted
|
| 3605 |
-
if 'file://' in html_doc and ('video' in html_doc.lower() or '.mp4' in html_doc.lower()):
|
| 3606 |
-
deployment_notice = '''
|
| 3607 |
-
<div style="
|
| 3608 |
-
position: fixed;
|
| 3609 |
-
top: 10px;
|
| 3610 |
-
right: 10px;
|
| 3611 |
-
background: #ff6b35;
|
| 3612 |
-
color: white;
|
| 3613 |
-
padding: 12px 16px;
|
| 3614 |
-
border-radius: 8px;
|
| 3615 |
-
font-family: Arial, sans-serif;
|
| 3616 |
-
font-size: 14px;
|
| 3617 |
-
font-weight: bold;
|
| 3618 |
-
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
| 3619 |
-
z-index: 9999;
|
| 3620 |
-
max-width: 300px;
|
| 3621 |
-
text-align: center;
|
| 3622 |
-
">
|
| 3623 |
-
Deploy app to see videos with permanent URLs!
|
| 3624 |
-
</div>
|
| 3625 |
-
'''
|
| 3626 |
-
# Insert the notice right after the opening body tag
|
| 3627 |
-
if '<body' in html_doc:
|
| 3628 |
-
body_end = html_doc.find('>', html_doc.find('<body')) + 1
|
| 3629 |
-
html_doc = html_doc[:body_end] + deployment_notice + html_doc[body_end:]
|
| 3630 |
-
else:
|
| 3631 |
-
html_doc = deployment_notice + html_doc
|
| 3632 |
|
| 3633 |
except Exception:
|
| 3634 |
# Best-effort; continue without inlining
|
|
@@ -3642,7 +3491,7 @@ def send_to_sandbox_with_refresh(code):
|
|
| 3642 |
"""Render HTML in a sandboxed iframe with cache-busting for media generation updates."""
|
| 3643 |
import time
|
| 3644 |
html_doc = (code or "").strip()
|
| 3645 |
-
# For preview only: inline local file URLs
|
| 3646 |
# data: iframe can load them. The original code (shown to the user) still contains file URLs.
|
| 3647 |
try:
|
| 3648 |
import re
|
|
@@ -3659,17 +3508,6 @@ def send_to_sandbox_with_refresh(code):
|
|
| 3659 |
raw = _f.read()
|
| 3660 |
mime = _mtypes.guess_type(path)[0] or 'application/octet-stream'
|
| 3661 |
|
| 3662 |
-
# Compress video files before converting to data URI to prevent preview breaks
|
| 3663 |
-
if mime and mime.startswith('video/'):
|
| 3664 |
-
print(f"[Sandbox] Compressing video for preview: {len(raw)} bytes")
|
| 3665 |
-
raw = compress_video_for_data_uri(raw, max_size_mb=1) # Very small limit for preview
|
| 3666 |
-
print(f"[Sandbox] Compressed video size: {len(raw)} bytes")
|
| 3667 |
-
|
| 3668 |
-
# If still too large, skip video embedding for preview
|
| 3669 |
-
if len(raw) > 512 * 1024: # 512KB final limit
|
| 3670 |
-
print(f"[Sandbox] Video still too large after compression, using placeholder")
|
| 3671 |
-
return None # Let the replacement function handle the fallback
|
| 3672 |
-
|
| 3673 |
b64 = _b64.b64encode(raw).decode()
|
| 3674 |
return f"data:{mime};base64,{b64}"
|
| 3675 |
except Exception as e:
|
|
@@ -3685,35 +3523,6 @@ def send_to_sandbox_with_refresh(code):
|
|
| 3685 |
return f"src='{data_uri}'" if data_uri else m.group(0)
|
| 3686 |
html_doc = re.sub(r'src="(file:[^"]+)"', _repl_double, html_doc)
|
| 3687 |
html_doc = re.sub(r"src='(file:[^']+)'", _repl_single, html_doc)
|
| 3688 |
-
|
| 3689 |
-
# Add deployment message for videos that couldn't be converted
|
| 3690 |
-
if 'file://' in html_doc and ('video' in html_doc.lower() or '.mp4' in html_doc.lower()):
|
| 3691 |
-
deployment_notice = '''
|
| 3692 |
-
<div style="
|
| 3693 |
-
position: fixed;
|
| 3694 |
-
top: 10px;
|
| 3695 |
-
right: 10px;
|
| 3696 |
-
background: #ff6b35;
|
| 3697 |
-
color: white;
|
| 3698 |
-
padding: 12px 16px;
|
| 3699 |
-
border-radius: 8px;
|
| 3700 |
-
font-family: Arial, sans-serif;
|
| 3701 |
-
font-size: 14px;
|
| 3702 |
-
font-weight: bold;
|
| 3703 |
-
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
| 3704 |
-
z-index: 9999;
|
| 3705 |
-
max-width: 300px;
|
| 3706 |
-
text-align: center;
|
| 3707 |
-
">
|
| 3708 |
-
Deploy app to see videos with permanent URLs!
|
| 3709 |
-
</div>
|
| 3710 |
-
'''
|
| 3711 |
-
# Insert the notice right after the opening body tag
|
| 3712 |
-
if '<body' in html_doc:
|
| 3713 |
-
body_end = html_doc.find('>', html_doc.find('<body')) + 1
|
| 3714 |
-
html_doc = html_doc[:body_end] + deployment_notice + html_doc[body_end:]
|
| 3715 |
-
else:
|
| 3716 |
-
html_doc = deployment_notice + html_doc
|
| 3717 |
|
| 3718 |
except Exception:
|
| 3719 |
# Best-effort; continue without inlining
|
|
@@ -4187,15 +3996,6 @@ Generate the exact search/replace blocks needed to make these changes."""
|
|
| 4187 |
else:
|
| 4188 |
session_id = str(uuid.uuid4())
|
| 4189 |
|
| 4190 |
-
# On each generate, reap old global files and cleanup previous session files
|
| 4191 |
-
try:
|
| 4192 |
-
cleanup_session_videos(session_id)
|
| 4193 |
-
cleanup_session_audio(session_id)
|
| 4194 |
-
reap_old_videos()
|
| 4195 |
-
reap_old_audio()
|
| 4196 |
-
except Exception:
|
| 4197 |
-
pass
|
| 4198 |
-
|
| 4199 |
# Update Gradio system prompts if needed
|
| 4200 |
if language == "gradio":
|
| 4201 |
update_gradio_system_prompts()
|
|
|
|
| 1526 |
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 1527 |
"""
|
| 1528 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1529 |
TRANSFORMERS_JS_SYSTEM_PROMPT = """You are an expert web developer creating a transformers.js application. You will generate THREE separate files: index.html, index.js, and style.css.
|
| 1530 |
|
| 1531 |
**🚨 CRITICAL: DO NOT Generate README.md Files**
|
|
|
|
| 3446 |
def send_to_sandbox(code):
|
| 3447 |
"""Render HTML in a sandboxed iframe. Assumes full HTML is provided by prompts."""
|
| 3448 |
html_doc = (code or "").strip()
|
| 3449 |
+
# For preview only: inline local file URLs as data URIs so the
|
| 3450 |
# data: iframe can load them. The original code (shown to the user) still contains file URLs.
|
| 3451 |
try:
|
| 3452 |
import re
|
|
|
|
| 3463 |
raw = _f.read()
|
| 3464 |
mime = _mtypes.guess_type(path)[0] or 'application/octet-stream'
|
| 3465 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3466 |
b64 = _b64.b64encode(raw).decode()
|
| 3467 |
return f"data:{mime};base64,{b64}"
|
| 3468 |
except Exception as e:
|
|
|
|
| 3478 |
return f"src='{data_uri}'" if data_uri else m.group(0)
|
| 3479 |
html_doc = re.sub(r'src="(file:[^"]+)"', _repl_double, html_doc)
|
| 3480 |
html_doc = re.sub(r"src='(file:[^']+)'", _repl_single, html_doc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3481 |
|
| 3482 |
except Exception:
|
| 3483 |
# Best-effort; continue without inlining
|
|
|
|
| 3491 |
"""Render HTML in a sandboxed iframe with cache-busting for media generation updates."""
|
| 3492 |
import time
|
| 3493 |
html_doc = (code or "").strip()
|
| 3494 |
+
# For preview only: inline local file URLs as data URIs so the
|
| 3495 |
# data: iframe can load them. The original code (shown to the user) still contains file URLs.
|
| 3496 |
try:
|
| 3497 |
import re
|
|
|
|
| 3508 |
raw = _f.read()
|
| 3509 |
mime = _mtypes.guess_type(path)[0] or 'application/octet-stream'
|
| 3510 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3511 |
b64 = _b64.b64encode(raw).decode()
|
| 3512 |
return f"data:{mime};base64,{b64}"
|
| 3513 |
except Exception as e:
|
|
|
|
| 3523 |
return f"src='{data_uri}'" if data_uri else m.group(0)
|
| 3524 |
html_doc = re.sub(r'src="(file:[^"]+)"', _repl_double, html_doc)
|
| 3525 |
html_doc = re.sub(r"src='(file:[^']+)'", _repl_single, html_doc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3526 |
|
| 3527 |
except Exception:
|
| 3528 |
# Best-effort; continue without inlining
|
|
|
|
| 3996 |
else:
|
| 3997 |
session_id = str(uuid.uuid4())
|
| 3998 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3999 |
# Update Gradio system prompts if needed
|
| 4000 |
if language == "gradio":
|
| 4001 |
update_gradio_system_prompts()
|