DocDoeAI / scripts /generate_premium_sound_waves_pilot.py
asnannp's picture
Deploy backend cd4237ff: support routes + rate limit + exam_date nullable + upload 413 fix
7c6ffa6
Raw
History Blame Contribute Delete
5.01 kB
from __future__ import annotations
import json
import os
import sys
from pathlib import Path
BACKEND_ROOT = Path(__file__).resolve().parents[1]
PROJECT_ROOT = BACKEND_ROOT.parent
os.environ["EDGE_TTS_VOICE_EN"] = "en-IN-PrabhatNeural"
os.environ["EDGE_TTS_RATE"] = "-6%"
if str(BACKEND_ROOT) not in sys.path:
sys.path.insert(0, str(BACKEND_ROOT))
from app.schemas.video import VideoScenePlanAudioInput # noqa: E402
from app.services.tts_provider import generate_audio_for_scene_plan # noqa: E402
VIDEO_ID = "premium-sound-waves-prabhat-v2"
OUTPUT_DIR = PROJECT_ROOT / "outputs" / "video" / "physics" / "sound-waves" / "premium-pilot"
def main() -> None:
scene_plan = {
"title": "How Sound Travels",
"duration_minutes": 1,
"language": "English",
"style": "kerala_sslc_teacher",
"scenes": [
{
"scene_id": 1,
"type": "experiment",
"duration_seconds": 20,
"screen_text": "Feel the vibration",
"voice_text": "Let us begin with something you can feel. Gently place two fingers on your throat. Now make a long ah sound. Feel that tiny movement? That is vibration. Every sound starts when something vibrates.",
"visual_kind": "experiment",
"key_line": "Sound begins with vibration.",
},
{
"scene_id": 2,
"type": "concept",
"duration_seconds": 24,
"screen_text": "The disturbance travels",
"voice_text": "Now watch the slinky. Squeeze one end of the spring and let it go. One part pushes the next part, but each part stays near its own place. What moves forward is the disturbance, not the slinky itself. Sound moves through air in the same way.",
"visual_kind": "slinky",
"key_line": "The disturbance travels; the particles only vibrate.",
"image_src": "assets/tuition/phy-p1-c1/img_30.png",
},
{
"scene_id": 3,
"type": "concept",
"duration_seconds": 27,
"screen_text": "Compression and rarefaction",
"voice_text": "Now let us name the two regions. When particles come closer, that crowded region is called a compression. When particles move farther apart, that spread-out region is called a rarefaction. The particles vibrate back and forth in the same direction as the wave. So sound in air is a longitudinal wave.",
"visual_kind": "compression",
"key_line": "Compression and rarefaction carry sound energy forward.",
"image_src": "assets/tuition/phy-p1-c1/img_30.png",
},
{
"scene_id": 4,
"type": "exam",
"duration_seconds": 22,
"screen_text": "Why no sound in vacuum?",
"voice_text": "Here is the one-mark exam answer. Why can sound not travel through a vacuum? Sound needs particles to pass vibration from one particle to the next. There are no particles inside a vacuum. Therefore, sound cannot travel through it.",
"visual_kind": "exam",
"key_line": "No particles means no sound.",
},
],
}
response = generate_audio_for_scene_plan(
scene_plan=VideoScenePlanAudioInput.model_validate(scene_plan),
voice_mode="english_soft",
voice="teacher_english",
language="English",
provider_name="edge",
video_id=VIDEO_ID,
use_cache=False,
)
scenes = response["updated_scene_plan"]["scenes"]
for original, generated in zip(scene_plan["scenes"], scenes, strict=True):
generated["visual_kind"] = original["visual_kind"]
generated["key_line"] = original["key_line"]
if original.get("image_src"):
generated["image_src"] = original["image_src"]
props = {
"title": scene_plan["title"],
"source": "Kerala SCERT · Standard X",
"music_src": "ad-music/bed.wav",
"music_volume": 0.055,
"scenes": scenes,
}
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
props_path = OUTPUT_DIR / "render-props.json"
props_path.write_text(json.dumps(props, indent=2, ensure_ascii=False), encoding="utf-8")
(OUTPUT_DIR / "narration-manifest.json").write_text(
json.dumps(
{
"provider": "edge",
"voice": "en-IN-PrabhatNeural",
"rate": "-6%",
"quality_gate": "whisper-medium transcript verification",
"scene_count": len(scenes),
"duration_seconds": sum(float(scene["duration_seconds"]) for scene in scenes),
},
indent=2,
),
encoding="utf-8",
)
print(json.dumps({"ok": True, "props": str(props_path), "scenes": len(scenes)}, indent=2))
if __name__ == "__main__":
main()