File size: 4,465 Bytes
7c6ffa6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Malayalam proof-of-concept for the Sound Waves opening — NOT a finished asset.

Translates the first few teaching phrases to Malayalam (Groq) and synthesizes
them with AI4Bharat's Anjali voice, so there is something concrete to review
before committing GPU-hours to a full Malayalam chapter. Machine-translated
science vocabulary needs a human check before it reaches a real class.
"""

from __future__ import annotations

import json
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "backend"))
sys.path.insert(0, str(ROOT / "backend" / "scripts"))

import importlib.util

kokoro_spec = importlib.util.spec_from_file_location("kokoro_chapter_audio", ROOT / "backend/scripts/generate_kokoro_chapter_audio.py")
kokoro_mod = importlib.util.module_from_spec(kokoro_spec)
kokoro_spec.loader.exec_module(kokoro_mod)

blueprint_spec = importlib.util.spec_from_file_location("blueprints", ROOT / "backend/scripts/generate_source_backed_science_blueprints.py")
blueprint_mod = importlib.util.module_from_spec(blueprint_spec)
blueprint_spec.loader.exec_module(blueprint_mod)

PHRASE_LIMIT = 6
OUTPUT_DIR = ROOT / "outputs" / "video" / "physics" / "malayalam-proof"


def translate_to_malayalam(generate_groq, text: str) -> str:
    prompt = f"""Translate this Kerala SSLC Class 10 Physics teacher's sentence into natural spoken Malayalam for text-to-speech.

Rules:
- Keep scientific terms Kerala students actually learn in English embedded as-is (e.g. compression, rarefaction, vibration, wavelength, frequency, longitudinal wave) — do not translate or transliterate them, just leave the English word inside the Malayalam sentence, matching how Malayalam-medium physics teachers really code-mix in class.
- Natural spoken rhythm, not a stiff word-for-word translation.
- Return ONLY the Malayalam sentence as a JSON object: {{"malayalam": "..."}}

English sentence:
{text}
"""
    result = generate_groq(prompt)
    return result["malayalam"]


def main() -> int:
    groq_key = blueprint_mod.env_value("GROQ_API_KEY")
    model = "meta-llama/llama-4-scout-17b-16e-instruct"
    generate_groq = lambda prompt: blueprint_mod.call_groq(prompt, groq_key, model)  # noqa: E731

    source_manifest_path = ROOT / "outputs/video/tuition/phy-p1-c1/audio/full-chapter/manifest.json"
    source_manifest = json.loads(source_manifest_path.read_text(encoding="utf-8"))
    merged = kokoro_mod.merge_scene_chunks(source_manifest["chunks"])[:PHRASE_LIMIT]

    import torch  # noqa: F401 - fail fast with a clear error if the wrong interpreter is used
    from app.schemas.video import VideoSceneAudioInput
    from app.services.tts_provider import AI4BharatIndicParlerTTSProvider

    provider = AI4BharatIndicParlerTTSProvider()
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    review_entries = []

    for index, phrase in enumerate(merged, start=1):
        malayalam_text = translate_to_malayalam(generate_groq, phrase["spokenText"])
        scene = VideoSceneAudioInput(scene_id=index, type="concept", duration_seconds=max(2.0, len(malayalam_text.split()) / 1.8), voice_text=malayalam_text)
        output_path = OUTPUT_DIR / f"{index:02d}-{phrase['sceneId']}.wav"
        result = provider.generate_scene_audio(scene=scene, output_file=output_path, voice_mode="malayalam_soft", voice="Anjali", language="ml")
        review_entries.append(
            {
                "index": index,
                "sceneId": phrase["sceneId"],
                "english": phrase["spokenText"],
                "malayalam_machine_translation": malayalam_text,
                "audioFile": str(output_path.relative_to(ROOT)).replace("\\", "/"),
                "durationSeconds": result.duration_seconds,
            }
        )
        print(f"[{index}/{len(merged)}] {phrase['sceneId']} synthesized", flush=True)

    manifest = {
        "warning": "MACHINE TRANSLATION, NOT HUMAN-REVIEWED. Verify every Malayalam line against actual Kerala SSLC physics terminology before using this in a real class video.",
        "chapterId": "phy-p1-c1",
        "voice": "Anjali",
        "phraseCount": len(review_entries),
        "entries": review_entries,
    }
    (OUTPUT_DIR / "review-manifest.json").write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
    print(f"Wrote {OUTPUT_DIR / 'review-manifest.json'}", flush=True)
    return 0


if __name__ == "__main__":
    sys.exit(main())