{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    },
    "colab": {
      "name": "DaVinci-Video-Studio.ipynb"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Da Vinci 4744 — סטודיו סרטונים בדפדפן\n",
        "הריצו את התאים לפי הסדר. העלו את `davinci-videos.zip`, ולא את החבילה המלאה.\n",
        "אפשר להעלות תוכנית JSON שנוצרה ב־ChatGPT או ב־Claude, או להריץ את דוגמת החללית עם הקריינות שכבר צורפה.\n",
        "יצירת קריינות חדשה דורשת מפתח Gemini API. המנוי לצ׳אט אינו מחליף אותו. המפתח נקלט דרך סודות Colab או שדה מוסתר, ולא נכתב לקובצי התוצאה.\n"
      ],
      "id": "davinci-01"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from pathlib import Path\n",
        "from zipfile import ZipFile\n",
        "import sys, subprocess, json, os, uuid\n",
        "from google.colab import files\n",
        "subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-q', 'Pillow>=11', 'numpy>=2', 'imageio-ffmpeg>=0.6', 'python-bidi>=0.6'])\n",
        "print('העלו את davinci-videos.zip')\n",
        "uploaded = files.upload()\n",
        "archive_name = next((name for name in uploaded if name.endswith('.zip')), None)\n",
        "if not archive_name: raise ValueError('נדרש קובץ ZIP של סקיל הסרטונים')\n",
        "destination = Path('/content') / ('davinci-studio-' + uuid.uuid4().hex[:8])\n",
        "destination.mkdir()\n",
        "with ZipFile(archive_name) as archive:\n",
        "    for item in archive.infolist():\n",
        "        if not (destination / item.filename).resolve().is_relative_to(destination):\n",
        "            raise ValueError('Invalid archive path')\n",
        "        if ((item.external_attr >> 16) & 0o170000) == 0o120000:\n",
        "            raise ValueError('Symlink entries are not supported')\n",
        "    archive.extractall(destination)\n",
        "skill = destination / 'davinci-videos'\n",
        "assert (skill / 'scripts/render_video.py').is_file(), 'נדרש ZIP שבו תיקיית davinci-videos בשורש'\n",
        "print('הערכה מוכנה')\n"
      ],
      "id": "davinci-02"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## תוכן הסרטון\n",
        "הקלידו `1` להעלאת תוכנית JSON חדשה, או `2` לדוגמת החללית המוכנה.\n",
        "התוכנית לדוגמה היא אותה פעילות בלבד. לשינוי נושא, השתמשו בתוכנית חדשה מהצ׳אט.\n"
      ],
      "id": "davinci-03"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "choice = input('1 = העלאת תוכנית חדשה, 2 = דוגמת החללית: ').strip()\n",
        "if choice == '1':\n",
        "    uploaded_plan = files.upload()\n",
        "    name = next((name for name in uploaded_plan if name.endswith('.json')), None)\n",
        "    if not name: raise ValueError('נדרש קובץ JSON של תוכנית הסצנות')\n",
        "    plan = skill / 'plans' / Path(name).name\n",
        "    plan.parent.mkdir(exist_ok=True)\n",
        "    plan.write_bytes(uploaded_plan[name])\n",
        "elif choice == '2':\n",
        "    plan = skill / 'examples/spaceship.json'\n",
        "else:\n",
        "    raise ValueError('בחרו 1 או 2')\n",
        "sys.path.insert(0, str(skill / 'scripts'))\n",
        "sys.modules.pop('plan_io', None)\n",
        "from plan_io import load_plan, valid_clip\n",
        "_, document, speech, work = load_plan(plan)\n",
        "print(document['title'], '|', len(document['scenes']), 'סצנות')\n"
      ],
      "id": "davinci-04"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## קריינות Gemini\n",
        "התא יוצר רק קטעים חדשים או ששונו. בדוגמה ללא שינויים הוא אינו פונה ל־API.\n",
        "לנוחותכם אפשר להוסיף מראש סוד ב־Colab בשם `GEMINI_API_KEY`.\n"
      ],
      "id": "davinci-05"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "missing = [scene for scene in document['scenes'] if not valid_clip(scene, speech, work)]\n",
        "if missing:\n",
        "    from getpass import getpass\n",
        "    try:\n",
        "        from google.colab import userdata\n",
        "        api_key = userdata.get('GEMINI_API_KEY')\n",
        "    except Exception:\n",
        "        api_key = None\n",
        "    if not api_key: api_key = getpass('Gemini API key (קלט מוסתר): ')\n",
        "    if not api_key: raise ValueError('לא הוגדר מפתח Gemini')\n",
        "    private_env = dict(os.environ)\n",
        "    private_env['GEMINI_API_KEY'] = api_key\n",
        "    try:\n",
        "        subprocess.run([sys.executable, str(skill / 'scripts/gemini_tts.py'), '--plan', str(plan)], env=private_env, check=True)\n",
        "    finally:\n",
        "        private_env.pop('GEMINI_API_KEY', None)\n",
        "        api_key = None\n",
        "else:\n",
        "    print('כל קטעי הקריינות תואמים לתוכנית. לא בוצעו קריאות API.')\n"
      ],
      "id": "davinci-06"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## רינדור והורדה\n",
        "הפקת Full HD יכולה לקחת זמן בהתאם לאורך הסרטון ולמשאבים הזמינים.\n",
        "התוצאה כוללת MP4, כתוביות SRT ותוכנית JSON. כתוביות אוטומטיות מתוזמנות בקירוב למשפטים.\n"
      ],
      "id": "davinci-07"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "subprocess.run([sys.executable, str(skill / 'scripts/render_video.py'), '--plan', str(plan), '--final'], check=True)\n",
        "result_zip = Path('/content/DaVinci-Video-Result.zip')\n",
        "with ZipFile(result_zip, 'w') as archive:\n",
        "    for file in (work / 'output').iterdir():\n",
        "        if file.is_file(): archive.write(file, file.name)\n",
        "    archive.write(plan, 'scene-plan.json')\n",
        "files.download(str(result_zip))\n"
      ],
      "id": "davinci-08"
    }
  ]
}
