File size: 4,342 Bytes
9fef5b9
 
 
 
 
 
b80eb6b
9fef5b9
c679f41
07976be
b80eb6b
c679f41
 
 
 
 
07976be
 
 
c679f41
07976be
 
c679f41
 
07976be
9fef5b9
b80eb6b
9fef5b9
 
b80eb6b
 
9fef5b9
 
 
b80eb6b
 
9fef5b9
 
 
b80eb6b
 
9fef5b9
 
 
b80eb6b
 
9fef5b9
 
 
b80eb6b
 
9fef5b9
 
b80eb6b
9fef5b9
 
b80eb6b
9fef5b9
 
 
 
 
 
 
 
 
b80eb6b
9fef5b9
 
 
 
 
b80eb6b
 
9fef5b9
b80eb6b
 
9fef5b9
b80eb6b
 
 
9fef5b9
b80eb6b
9fef5b9
b80eb6b
07976be
b80eb6b
 
 
 
 
 
 
 
 
 
 
 
9fef5b9
07976be
 
9fef5b9
b80eb6b
9fef5b9
b80eb6b
 
 
 
 
 
 
 
 
 
 
 
 
9fef5b9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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

# Initialize Coqui TTS (Tacotron2-DDC)
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

# Agents definitions
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'."
)

# Orchestrator
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

    # Synthesize voiceover
    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"])

    # Render slides
    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))

    # Bundle into ZIP
    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

# Gradio UI
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()