bytebrains / app.py
Sanket17's picture
Update app.py
38ca683 verified
import os
import sys
import subprocess
import tempfile
import logging
from pathlib import Path
from datetime import datetime
import gradio as gr
# ── Logging setup ─────────────────────────────────────────────────────────────
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.StreamHandler(sys.stdout)]
)
log = logging.getLogger(__name__)
HERE = Path(__file__).parent.resolve()
LOGO_PATH = HERE / "logo" / "logo.png"
RUN_PIPELINE = HERE / "run_pipeline.py"
log.info("=== ByteBrain starting up ===")
log.info(f"Working directory : {HERE}")
log.info(f"Python executable : {sys.executable}")
log.info(f"run_pipeline.py exists: {RUN_PIPELINE.exists()}")
def _slug(text: str) -> str:
return "".join(ch.lower() if ch.isalnum() else "_" for ch in text).strip("_")
def generate_video(topic: str):
topic = (topic or "").strip()
if not topic:
raise gr.Error("Please enter a topic.")
log.info(f"Generate requested β€” topic: '{topic}'")
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
output_root = Path(tempfile.gettempdir()) / "bytebrain-output"
output_root.mkdir(parents=True, exist_ok=True)
output_video = output_root / f"{_slug(topic)}_{ts}_video.mp4"
log.info(f"Output path: {output_video}")
env = os.environ.copy() # passes all HF Secrets automatically
env["PIPELINE_OUTPUT_DIR"] = str(output_root)
env["PYTHONIOENCODING"] = "utf-8"
env["PYTHONUTF8"] = "1"
cmd = [
sys.executable,
"-X", "utf8",
str(RUN_PIPELINE),
topic,
"--output", str(output_video),
]
log.info(f"Running command: {' '.join(cmd)}")
proc = subprocess.run(
cmd,
capture_output=True,
encoding="utf-8",
errors="replace",
cwd=str(HERE),
env=env,
)
logs = (proc.stdout or "") + ("\n" + proc.stderr if proc.stderr else "")
log.info(f"Pipeline exited with code: {proc.returncode}")
if proc.stdout:
log.info(f"STDOUT:\n{proc.stdout[-2000:]}")
if proc.stderr:
log.warning(f"STDERR:\n{proc.stderr[-2000:]}")
if proc.returncode != 0:
tail = "\n".join(logs.strip().splitlines()[-50:])
log.error("Pipeline failed.")
raise gr.Error(f"Generation failed.\n{tail}")
if not output_video.exists():
log.error("Output video file missing after pipeline run.")
raise gr.Error("Pipeline finished but output video file is missing.")
log.info("Video generation successful.")
return str(output_video), logs
# ── Gradio UI ─────────────────────────────────────────────────────────────────
with gr.Blocks(title="ByteBrain Video Generator") as demo:
if LOGO_PATH.exists():
gr.Image(value=str(LOGO_PATH), show_label=False, width=140, height=140)
gr.Markdown("## ByteBrain β€” Topic to Video")
gr.Markdown(
"Enter any ML/CS topic and get a chalkboard explainer video "
"with Hindi Trump-Modi narration."
)
topic_input = gr.Textbox(label="Topic", placeholder="e.g. Softmax Function")
generate_btn = gr.Button("Generate Video", variant="primary")
video_output = gr.Video(label="Generated Video")
logs_output = gr.Textbox(label="Pipeline Logs", lines=20, max_lines=40)
generate_btn.click(
fn=generate_video,
inputs=topic_input,
outputs=[video_output, logs_output],
)
log.info("Gradio UI built successfully.")
if __name__ == "__main__":
demo.queue().launch(
server_name="0.0.0.0",
server_port=7860,
show_error=True,
root_path="/", # fixes localhost detection in Docker
)