|
import os |
|
import json |
|
import tempfile |
|
from zipfile import ZipFile |
|
|
|
import gradio as gr |
|
from agents import Agent, handoff, Runner |
|
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX |
|
from TTS.api import TTS |
|
|
|
|
|
tts = TTS( |
|
model_name="tts_models/en/ljspeech/tacotron2-DDC", |
|
progress_bar=False, |
|
gpu=False |
|
) |
|
|
|
def generate_tts_audio(script: str) -> str: |
|
""" |
|
Synthesize speech using Coqui TTS and save to a WAV file. |
|
Returns the local file path to the audio. |
|
""" |
|
out_path = os.path.join(tempfile.gettempdir(), "voiceover.wav") |
|
tts.tts_to_file(text=script, file_path=out_path) |
|
return out_path |
|
|
|
|
|
topic_agent = Agent( |
|
name="Topic Agent", |
|
instructions=f"{RECOMMENDED_PROMPT_PREFIX}\n" |
|
"You are given a workshop topic and audience. Draft a structured learning path: goals, 4 modules, and a hands-on exercise for each." |
|
) |
|
content_agent = Agent( |
|
name="Content Agent", |
|
instructions=f"{RECOMMENDED_PROMPT_PREFIX}\n" |
|
"Convert the outline into detailed module scripts, speaker notes, and 3 quiz questions per module." |
|
) |
|
slide_agent = Agent( |
|
name="Slide Agent", |
|
instructions=f"{RECOMMENDED_PROMPT_PREFIX}\n" |
|
"Given module content, produce slide JSON with title, bullet points, and design hints." |
|
) |
|
code_agent = Agent( |
|
name="Code Agent", |
|
instructions=f"{RECOMMENDED_PROMPT_PREFIX}\n" |
|
"Generate runnable Python code snippets or a Colab notebook for hands-on labs in each module." |
|
) |
|
voice_agent = Agent( |
|
name="Voiceover Agent", |
|
instructions=f"{RECOMMENDED_PROMPT_PREFIX}\n" |
|
"Create a 1-2 minute voiceover script. Return JSON with key 'script'." |
|
) |
|
|
|
|
|
document_orchestrator = Agent( |
|
name="Workshop Orchestrator", |
|
instructions="Invoke: topic_agent, content_agent, slide_agent, code_agent, voice_agent (optional); collect outputs.", |
|
handoffs=[ |
|
handoff(topic_agent, name="outline"), |
|
handoff(content_agent, name="content"), |
|
handoff(slide_agent, name="slides"), |
|
handoff(code_agent, name="code_labs"), |
|
handoff(voice_agent, name="voiceover", optional=True), |
|
] |
|
) |
|
|
|
runner = Runner() |
|
|
|
def build_workshop_bundle(topic: str, audience: str): |
|
prompt = f"Create a {topic} workshop for {audience}." |
|
results = runner.run(document_orchestrator, prompt).outputs |
|
|
|
|
|
voice_info = results.get("voiceover", {}) |
|
audio_path = None |
|
if isinstance(voice_info, dict) and "script" in voice_info: |
|
audio_path = generate_tts_audio(voice_info["script"]) |
|
|
|
|
|
slides_json = results.get("slides", {}) |
|
with open("static/slides_template.html") as f: |
|
template = f.read() |
|
slide_html = template.replace("{{SLIDES_JSON}}", json.dumps(slides_json)) |
|
|
|
|
|
tmpdir = tempfile.mkdtemp() |
|
zip_path = os.path.join(tmpdir, "workshop_bundle.zip") |
|
with ZipFile(zip_path, "w") as zipf: |
|
for name, content in [ |
|
("workshop_outputs.json", json.dumps(results, indent=2)), |
|
("slides.json", json.dumps(slides_json, indent=2)), |
|
("slides.html", slide_html), |
|
("code_labs.py", results.get("code_labs", "")), |
|
]: |
|
p = os.path.join(tmpdir, name) |
|
with open(p, "w") as file: |
|
file.write(content) |
|
zipf.write(p, arcname=name) |
|
if audio_path and os.path.exists(audio_path): |
|
zipf.write(audio_path, os.path.basename(audio_path)) |
|
return slide_html, audio_path, zip_path |
|
|
|
|
|
def run_app(topic, audience): |
|
return build_workshop_bundle(topic, audience) |
|
|
|
with gr.Blocks(title="π Workshop in a Box") as demo: |
|
gr.Markdown("# Workshop in a Box") |
|
topic = gr.Textbox(label="Workshop Topic", placeholder="e.g., AI Agents 101") |
|
audience = gr.Textbox(label="Audience", placeholder="e.g., Product Managers") |
|
btn = gr.Button("Generate Workshop") |
|
slide_preview = gr.HTML(label="Slide Preview") |
|
audio_player = gr.Audio(label="Voiceover Preview", interactive=True) |
|
download = gr.File(label="Download ZIP") |
|
btn.click(fn=run_app, inputs=[topic, audience], outputs=[slide_preview, audio_player, download]) |
|
|
|
if __name__ == "__main__": |
|
demo.launch() |