File size: 5,371 Bytes
c679f41 07976be 9fef5b9 c679f41 07976be c679f41 07976be c679f41 07976be c679f41 07976be 9fef5b9 c679f41 9fef5b9 07976be 9fef5b9 07976be 9fef5b9 07976be 9fef5b9 07976be 9fef5b9 07976be c679f41 07976be c679f41 07976be 9fef5b9 07976be 9fef5b9 c679f41 9fef5b9 07976be 9fef5b9 07976be 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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
## 1. `app.py`
import os
import json
import tempfile
from zipfile import ZipFile
import gradio as gr
from agents import Agent, AgentRunner, handoff
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX
# === Coqui TTS Integration ===
from TTS.api import TTS
# Initialize Coqui TTS (choose a model)
# Using Tacotron2-DDC model from LJSpeech
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.
"""
# Determine output path in temp directory
out_path = os.path.join(tempfile.gettempdir(), "voiceover.wav")
# Render the speech to the file
tts.tts_to_file(text=script, file_path=out_path)
return out_path
# --- Multi-Agent Scaffold ---
# 1. Topic Agent
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."
)
)
# 2. Content Agent
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."
)
)
# 3. Slide Agent
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."
)
)
# 4. Code Agent
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."
)
)
# 5. Voiceover Agent (Optional)
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: sequences agents
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 = AgentRunner()
# --- Helper: Run pipeline & bundle outputs ---
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 if script present
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 to HTML
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))
# Create a ZIP bundle
tmpdir = tempfile.mkdtemp()
zip_path = os.path.join(tmpdir, 'workshop_bundle.zip')
with ZipFile(zip_path, 'w') as zipf:
# JSON outputs
out_json = os.path.join(tmpdir, 'workshop_outputs.json')
with open(out_json, 'w') as jf:
jf.write(json.dumps(results, indent=2))
zipf.write(out_json, 'workshop_outputs.json')
# Slides JSON & HTML
slide_json_file = os.path.join(tmpdir, 'slides.json')
with open(slide_json_file, 'w') as sf:
sf.write(json.dumps(slides_json, indent=2))
zipf.write(slide_json_file, 'slides.json')
slide_html_file = os.path.join(tmpdir, 'slides.html')
with open(slide_html_file, 'w') as hf:
hf.write(slide_html)
zipf.write(slide_html_file, 'slides.html')
# Code labs
code_file = os.path.join(tmpdir, 'code_labs.py')
with open(code_file, 'w') as cf:
cf.write(results.get('code_labs', ''))
zipf.write(code_file, 'code_labs.py')
# Audio
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):
slide_html, audio_path, zip_path = build_workshop_bundle(topic, audience)
return slide_html, audio_path, zip_path
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() |