diff --git a/docs/OmniVoice.ipynb b/docs/OmniVoice.ipynb index b440f314..fd25821c 100644 --- a/docs/OmniVoice.ipynb +++ b/docs/OmniVoice.ipynb @@ -1,144 +1,414 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": "# OmniVoice Quick Start\n\n[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/k2-fsa/OmniVoice/blob/master/docs/OmniVoice.ipynb)\n\nThis notebook demonstrates the basic usage of [OmniVoice](https://github.com/k2-fsa/OmniVoice), a massively multilingual zero-shot TTS model supporting 600+ languages.\n\n**Contents:**\n1. Installation\n2. Option A — Gradio Demo (interactive web UI, no code needed)\n3. Option B — Python API\n - 3.1 Load Model\n - 3.2 Voice Cloning\n - 3.3 Voice Design\n - 3.4 Auto Voice" + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9V951npOrgmk" + }, + "source": [ + "# OmniVoice Quick Start\n", + "\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/k2-fsa/OmniVoice/blob/master/docs/OmniVoice.ipynb)\n", + "\n", + "This notebook demonstrates the basic usage of [OmniVoice](https://github.com/k2-fsa/OmniVoice), a massively multilingual zero-shot TTS model supporting 600+ languages.\n", + "\n", + "**Contents:**\n", + "1. Installation\n", + "2. Option A — Gradio Demo (interactive web UI, no code needed)\n", + "3. Option B — Python API\n", + " - 3.1 Load Model\n", + " - 3.2 Voice Cloning\n", + " - 3.3 Voice Design\n", + " - 3.4 Auto Voice" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DJLIA1gCrgml" + }, + "source": [ + "## 1. Installation\n", + "\n", + "Colab already provides a compatible PyTorch + CUDA environment, so we only need to install OmniVoice." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "VmpU9ESvrgml", + "outputId": "68cc704d-08eb-4432-e6c3-a4b6dd2d231c", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Collecting omnivoice\n", + " Downloading omnivoice-0.1.5-py3-none-any.whl.metadata (14 kB)\n", + "Requirement already satisfied: accelerate in /usr/local/lib/python3.12/dist-packages (from omnivoice) (1.14.0)\n", + "Requirement already satisfied: gradio in /usr/local/lib/python3.12/dist-packages (from omnivoice) (6.19.0)\n", + "Requirement already satisfied: librosa in /usr/local/lib/python3.12/dist-packages (from omnivoice) (0.11.0)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.12/dist-packages (from omnivoice) (2.0.2)\n", + "Requirement already satisfied: pydub in /usr/local/lib/python3.12/dist-packages (from omnivoice) (0.25.1)\n", + "Requirement already satisfied: soundfile in /usr/local/lib/python3.12/dist-packages (from omnivoice) (0.14.0)\n", + "Collecting tensorboardx (from omnivoice)\n", + " Downloading tensorboardx-2.6.5-py3-none-any.whl.metadata (6.6 kB)\n", + "Requirement already satisfied: torch>=2.4 in /usr/local/lib/python3.12/dist-packages (from omnivoice) (2.11.0+cpu)\n", + "Requirement already satisfied: torchaudio>=2.4 in /usr/local/lib/python3.12/dist-packages (from omnivoice) (2.11.0+cpu)\n", + "Requirement already satisfied: transformers>=5.3.0 in /usr/local/lib/python3.12/dist-packages (from omnivoice) (5.12.1)\n", + "Collecting webdataset (from omnivoice)\n", + " Downloading webdataset-1.0.2-py3-none-any.whl.metadata (12 kB)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.12/dist-packages (from torch>=2.4->omnivoice) (3.29.4)\n", + "Requirement already satisfied: typing-extensions>=4.10.0 in /usr/local/lib/python3.12/dist-packages (from torch>=2.4->omnivoice) (4.15.0)\n", + "Requirement already satisfied: setuptools<82 in /usr/local/lib/python3.12/dist-packages (from torch>=2.4->omnivoice) (75.2.0)\n", + "Requirement already satisfied: sympy>=1.13.3 in /usr/local/lib/python3.12/dist-packages (from torch>=2.4->omnivoice) (1.14.0)\n", + "Requirement already satisfied: networkx>=2.5.1 in /usr/local/lib/python3.12/dist-packages (from torch>=2.4->omnivoice) (3.6.1)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.12/dist-packages (from torch>=2.4->omnivoice) (3.1.6)\n", + "Requirement already satisfied: fsspec>=0.8.5 in /usr/local/lib/python3.12/dist-packages (from torch>=2.4->omnivoice) (2025.3.0)\n", + "Requirement already satisfied: huggingface-hub<2.0,>=1.5.0 in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (1.20.1)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (26.2)\n", + "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (6.0.3)\n", + "Requirement already satisfied: regex>=2025.10.22 in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (2025.11.3)\n", + "Requirement already satisfied: tokenizers<=0.23.0,>=0.22.0 in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (0.22.2)\n", + "Requirement already satisfied: typer in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (0.25.1)\n", + "Requirement already satisfied: safetensors>=0.4.3 in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (0.8.0)\n", + "Requirement already satisfied: tqdm>=4.60 in /usr/local/lib/python3.12/dist-packages (from transformers>=5.3.0->omnivoice) (4.67.3)\n", + "Requirement already satisfied: psutil in /usr/local/lib/python3.12/dist-packages (from accelerate->omnivoice) (5.9.5)\n", + "Requirement already satisfied: anyio<5.0,>=3.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (4.14.0)\n", + "Requirement already satisfied: brotli>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (1.2.0)\n", + "Requirement already satisfied: fastapi<1.0,>=0.115.2 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.138.0)\n", + "Requirement already satisfied: gradio-client==2.5.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (2.5.0)\n", + "Requirement already satisfied: groovy~=0.1 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.1.2)\n", + "Requirement already satisfied: hf-gradio<1.0,>=0.4.1 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.4.1)\n", + "Requirement already satisfied: httpx<1.0,>=0.24.1 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.28.1)\n", + "Requirement already satisfied: markupsafe<4.0,>=2.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (3.0.3)\n", + "Requirement already satisfied: orjson~=3.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (3.11.9)\n", + "Requirement already satisfied: pandas<4.0,>=1.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (2.2.2)\n", + "Requirement already satisfied: pillow<13.0,>=8.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (11.3.0)\n", + "Requirement already satisfied: pydantic<=3.0,>=2.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (2.13.4)\n", + "Requirement already satisfied: python-multipart<1.0,>=0.0.18 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.0.32)\n", + "Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (2025.2)\n", + "Requirement already satisfied: safehttpx<0.2.0,>=0.1.7 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.1.7)\n", + "Requirement already satisfied: semantic-version~=2.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (2.10.0)\n", + "Requirement already satisfied: starlette<2.0,>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (1.3.1)\n", + "Requirement already satisfied: tomlkit<0.15.0,>=0.12.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.14.0)\n", + "Requirement already satisfied: uvicorn>=0.14.0 in /usr/local/lib/python3.12/dist-packages (from gradio->omnivoice) (0.49.0)\n", + "Requirement already satisfied: audioread>=2.1.9 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (3.1.0)\n", + "Requirement already satisfied: numba>=0.51.0 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (0.60.0)\n", + "Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (1.16.3)\n", + "Requirement already satisfied: scikit-learn>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (1.6.1)\n", + "Requirement already satisfied: joblib>=1.0 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (1.5.3)\n", + "Requirement already satisfied: decorator>=4.3.0 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (4.4.2)\n", + "Requirement already satisfied: pooch>=1.1 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (1.9.0)\n", + "Requirement already satisfied: soxr>=0.3.2 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (1.1.0)\n", + "Requirement already satisfied: lazy_loader>=0.1 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (0.5)\n", + "Requirement already satisfied: msgpack>=1.0 in /usr/local/lib/python3.12/dist-packages (from librosa->omnivoice) (1.2.1)\n", + "Requirement already satisfied: cffi>=1.0 in /usr/local/lib/python3.12/dist-packages (from soundfile->omnivoice) (2.0.0)\n", + "Requirement already satisfied: protobuf>=3.20 in /usr/local/lib/python3.12/dist-packages (from tensorboardx->omnivoice) (5.29.6)\n", + "Collecting braceexpand (from webdataset->omnivoice)\n", + " Downloading braceexpand-0.1.7-py2.py3-none-any.whl.metadata (3.0 kB)\n", + "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.12/dist-packages (from anyio<5.0,>=3.0->gradio->omnivoice) (3.18)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.12/dist-packages (from cffi>=1.0->soundfile->omnivoice) (3.0)\n", + "Requirement already satisfied: typing-inspection>=0.4.2 in /usr/local/lib/python3.12/dist-packages (from fastapi<1.0,>=0.115.2->gradio->omnivoice) (0.4.2)\n", + "Requirement already satisfied: annotated-doc>=0.0.2 in /usr/local/lib/python3.12/dist-packages (from fastapi<1.0,>=0.115.2->gradio->omnivoice) (0.0.4)\n", + "Requirement already satisfied: certifi in /usr/local/lib/python3.12/dist-packages (from httpx<1.0,>=0.24.1->gradio->omnivoice) (2026.6.17)\n", + "Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.12/dist-packages (from httpx<1.0,>=0.24.1->gradio->omnivoice) (1.0.9)\n", + "Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.12/dist-packages (from httpcore==1.*->httpx<1.0,>=0.24.1->gradio->omnivoice) (0.16.0)\n", + "Requirement already satisfied: click>=8.4.0 in /usr/local/lib/python3.12/dist-packages (from huggingface-hub<2.0,>=1.5.0->transformers>=5.3.0->omnivoice) (8.4.2)\n", + "Requirement already satisfied: hf-xet<2.0.0,>=1.5.1 in /usr/local/lib/python3.12/dist-packages (from huggingface-hub<2.0,>=1.5.0->transformers>=5.3.0->omnivoice) (1.5.1)\n", + "Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/local/lib/python3.12/dist-packages (from numba>=0.51.0->librosa->omnivoice) (0.43.0)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas<4.0,>=1.0->gradio->omnivoice) (2.9.0.post0)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas<4.0,>=1.0->gradio->omnivoice) (2026.2)\n", + "Requirement already satisfied: platformdirs>=2.5.0 in /usr/local/lib/python3.12/dist-packages (from pooch>=1.1->librosa->omnivoice) (4.10.0)\n", + "Requirement already satisfied: requests>=2.19.0 in /usr/local/lib/python3.12/dist-packages (from pooch>=1.1->librosa->omnivoice) (2.32.4)\n", + "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.12/dist-packages (from pydantic<=3.0,>=2.0->gradio->omnivoice) (0.7.0)\n", + "Requirement already satisfied: pydantic-core==2.46.4 in /usr/local/lib/python3.12/dist-packages (from pydantic<=3.0,>=2.0->gradio->omnivoice) (2.46.4)\n", + "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn>=1.1.0->librosa->omnivoice) (3.6.0)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from sympy>=1.13.3->torch>=2.4->omnivoice) (1.3.0)\n", + "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.12/dist-packages (from typer->transformers>=5.3.0->omnivoice) (1.5.4)\n", + "Requirement already satisfied: rich>=13.8.0 in /usr/local/lib/python3.12/dist-packages (from typer->transformers>=5.3.0->omnivoice) (13.9.4)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.2->pandas<4.0,>=1.0->gradio->omnivoice) (1.17.0)\n", + "Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests>=2.19.0->pooch>=1.1->librosa->omnivoice) (3.4.7)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests>=2.19.0->pooch>=1.1->librosa->omnivoice) (2.5.0)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.12/dist-packages (from rich>=13.8.0->typer->transformers>=5.3.0->omnivoice) (4.2.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.12/dist-packages (from rich>=13.8.0->typer->transformers>=5.3.0->omnivoice) (2.20.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.12/dist-packages (from markdown-it-py>=2.2.0->rich>=13.8.0->typer->transformers>=5.3.0->omnivoice) (0.1.2)\n", + "Downloading omnivoice-0.1.5-py3-none-any.whl (162 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m162.5/162.5 kB\u001b[0m \u001b[31m5.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading tensorboardx-2.6.5-py3-none-any.whl (87 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m87.5/87.5 kB\u001b[0m \u001b[31m4.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading webdataset-1.0.2-py3-none-any.whl (74 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.0/75.0 kB\u001b[0m \u001b[31m3.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading braceexpand-0.1.7-py2.py3-none-any.whl (5.9 kB)\n", + "Installing collected packages: braceexpand, webdataset, tensorboardx, omnivoice\n", + "Successfully installed braceexpand-0.1.7 omnivoice-0.1.5 tensorboardx-2.6.5 webdataset-1.0.2\n" + ] + } + ], + "source": [ + "!pip install omnivoice" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YDyT7msKrgml" + }, + "source": [ + "## 2. Option A — Gradio Demo\n", + "\n", + "Launch an interactive web UI with a public Gradio link. The `--share` flag creates a temporary public URL so you can access the demo from any browser.\n", + "\n", + "> **If you prefer to use the Python API directly, skip to Option B below.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "heJGqi5Crgml", + "outputId": "d114e27a-cbc7-4663-df4a-39dff5ba1bab", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "/usr/local/lib/python3.12/dist-packages/pydub/utils.py:300: SyntaxWarning: invalid escape sequence '\\('\n", + " m = re.match('([su]([0-9]{1,2})p?) \\(([0-9]{1,2}) bit\\)$', token)\n", + "/usr/local/lib/python3.12/dist-packages/pydub/utils.py:301: SyntaxWarning: invalid escape sequence '\\('\n", + " m2 = re.match('([su]([0-9]{1,2})p?)( \\(default\\))?$', token)\n", + "/usr/local/lib/python3.12/dist-packages/pydub/utils.py:310: SyntaxWarning: invalid escape sequence '\\('\n", + " elif re.match('(flt)p?( \\(default\\))?$', token):\n", + "/usr/local/lib/python3.12/dist-packages/pydub/utils.py:314: SyntaxWarning: invalid escape sequence '\\('\n", + " elif re.match('(dbl)p?( \\(default\\))?$', token):\n", + "2026-07-01 07:58:04,099 root INFO: Loading model from k2-fsa/OmniVoice, device=cpu ...\n", + "Downloading (incomplete total...): 0.00B [00:00, ?B/s]\n", + "Fetching 13 files: 0% 0/13 [00:00 **If you prefer to use the Python API directly, skip to Option B below.**" - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!omnivoice-demo --share" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": "## 3. Option B — Python API\n\n### 3.1 Load Model" - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": "from omnivoice import OmniVoice\nimport soundfile as sf\nimport torch\nfrom IPython.display import Audio, display\n\nmodel = OmniVoice.from_pretrained(\n \"k2-fsa/OmniVoice\",\n device_map=\"cuda:0\",\n dtype=torch.float16,\n load_asr=True,\n)" - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": "### 3.2 Voice Cloning\n\nClone a voice from a short (3-10s) reference audio clip. Upload your own `ref.wav` or use any audio file.\n\n`ref_text` is optional — if omitted, the model uses Whisper ASR to auto-transcribe it." - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from google.colab import files\n", - "\n", - "print(\"Upload a reference audio file (wav/mp3/flac):\")\n", - "uploaded = files.upload()\n", - "ref_audio_path = list(uploaded.keys())[0]\n", - "print(f\"Uploaded: {ref_audio_path}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "audio = model.generate(\n", - " text=\"Hello, this is a test of zero-shot voice cloning.\",\n", - " ref_audio=ref_audio_path,\n", - " # ref_text=\"Transcription of the reference audio.\", # optional\n", - ")\n", - "\n", - "sf.write(\"clone_out.wav\", audio[0], 24000)\n", - "display(Audio(audio[0], rate=24000))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": "### 3.3 Voice Design\n\nDescribe the desired voice with speaker attributes — no reference audio needed.\n\nSupported attributes: gender, age, pitch, style (whisper), English accent, Chinese dialect. See [docs/voice-design.md](https://github.com/k2-fsa/OmniVoice/blob/master/docs/voice-design.md) for the full list." - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "audio = model.generate(\n", - " text=\"Hello, this is a test of zero-shot voice design.\",\n", - " instruct=\"female, low pitch, british accent\",\n", - ")\n", - "\n", - "sf.write(\"design_out.wav\", audio[0], 24000)\n", - "display(Audio(audio[0], rate=24000))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": "### 3.4 Auto Voice\n\nLet the model choose a voice automatically — no reference audio or instruct needed." - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "audio = model.generate(\n", - " text=\"This is a sentence generated with automatic voice selection.\",\n", - ")\n", - "\n", - "sf.write(\"auto_out.wav\", audio[0], 24000)\n", - "display(Audio(audio[0], rate=24000))" - ] - } - ], - "metadata": { - "accelerator": "GPU", - "colab": { - "gpuType": "T4", - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "name": "python", - "version": "3.10.0" - } - }, - "nbformat": 4, - "nbformat_minor": 0 + "nbformat": 4, + "nbformat_minor": 0 } \ No newline at end of file