Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cell execution telemetry #2610

Draft
wants to merge 10 commits into
base: latest
Choose a base branch
from
10 changes: 10 additions & 0 deletions .ci/check_notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from patch_notebooks import DEVICE_WIDGET, DEVICE_WIDGET_NEW
from install_instructions import check_install_instructions
from scarf_pixel import check_scarf_tag
from telemetry_snippet import check_telemetry_snippet
from pathlib import Path

NOTEBOOKS_ROOT = Path(__file__).resolve().parents[1]
Expand Down Expand Up @@ -34,6 +35,7 @@ def main():
no_tocs = []
no_device = []
no_scarf_tag = []
no_telemetry_snippet = []
no_install_instructions = []

def complain(message):
Expand Down Expand Up @@ -73,6 +75,9 @@ def complain(message):
if not check_scarf_tag(nb_path):
no_scarf_tag.append(str(nb_path.relative_to(NOTEBOOKS_ROOT)))
complain(f"FAILED: {nb_path.relative_to(NOTEBOOKS_ROOT)}: Scarf Pixel tag is not found")
if not check_telemetry_snippet(nb_path):
no_telemetry_snippet.append(str(nb_path.relative_to(NOTEBOOKS_ROOT)))
complain(f"FAILED: {nb_path.relative_to(NOTEBOOKS_ROOT)}: telemetry snippet is not found")
if not check_install_instructions(nb_path):
no_install_instructions.append(str(nb_path.relative_to(NOTEBOOKS_ROOT)))
complain(f"FAILED: {nb_path.relative_to(NOTEBOOKS_ROOT)}: Install Instructions section is not found")
Expand All @@ -94,6 +99,11 @@ def complain(message):
print("\n".join(no_scarf_tag))
print("\nYou can generate Scarf Pixel tag with the following command:\n python .ci/scarf_pixel.py -s <PATH>")
print("==================================")
if no_telemetry_snippet:
print("NO TELEMETRY SNIPPET:")
print("\n".join(no_telemetry_snippet))
print("\nYou can generate telemetry snippet with the following command:\n python .ci/telemetry_snippet.py -s <PATH>")
print("==================================")
if no_install_instructions:
print("NO INSTALL INSTRUCTIONS SECTION:")
print("\n".join(no_install_instructions))
Expand Down
72 changes: 72 additions & 0 deletions .ci/telemetry_snippet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import argparse
from pathlib import Path
import nbformat

REPO_ROOT = Path(__file__).resolve().parents[1]


def _get_telemetry_snippet(notebook_path: Path) -> str:
if notebook_path.is_absolute():
notebook_path = notebook_path.relative_to(REPO_ROOT)
return "".join(
[
"# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry\n",
"from notebook_utils import collect_telemetry\n",
f'collect_telemetry("{notebook_path.name}")',
]
)


def check_telemetry_snippet(notebook_path: Path) -> bool:
if notebook_path.suffix != ".ipynb":
print(f'Invalid file extension at path "{str(notebook_path)}". Only .ipynb files are supported.')
return False
telemetry_snippet = _get_telemetry_snippet(notebook_path)
with open(notebook_path, "r") as notebook_file:
nb_node: nbformat.NotebookNode = nbformat.read(notebook_file, as_version=4)
for cell in nb_node["cells"]:
if cell["cell_type"] != "code":
continue
cell_content: str = cell["source"]
if telemetry_snippet in cell_content:
return True
return False


def _add_telemetry_snippet(notebook_path: Path):
if notebook_path.suffix != ".ipynb":
raise Exception(f'Invalid file extension at path "{str(notebook_path)}". Only .ipynb files are supported.')
with open(notebook_path, "r") as fr:
nb_node: nbformat.NotebookNode = nbformat.read(fr, as_version=4)
# Find cell with notebook_utils
notebook_utils_url = "https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/utils/notebook_utils.py"
for i, cell in enumerate(nb_node["cells"]):
if cell["cell_type"] != "code":
continue
cell_content: str = cell["source"]
if notebook_utils_url in cell_content:
nb_node["cells"][i]["source"] = cell_content + "\n\n" + _get_telemetry_snippet(notebook_path)
break
with open(notebook_path, "w") as fw:
nbformat.write(nb_node, fw)


if __name__ == "__main__":
parser = argparse.ArgumentParser()

parser.add_argument(
"-s",
"--source",
help="Specify the path to the notebook file, where telemetry snippet should be added",
required=True,
)

args = parser.parse_args()
file_path = Path(args.source)
if not file_path.exists():
print(f'File does not exist at path "{file_path}"')
exit(1)
if not file_path.is_file():
print(f"Provided path is not a file")
exit(1)
_add_telemetry_snippet(file_path)
8 changes: 7 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,13 @@ To do this, there are a few requirements that all notebooks need to pass.
5. Add **Table of content** to top of the Notebook, it helps to get quick fist understanding of content and ease of navigation in the dev environment. There is no need to think about it during development, it can be built or updated after changes with `.ci\table_of_content.py`. Just run the script with the parameter `-s/--source`, specifying a Notebook or a folder with several notebooks as value, the changes will be applied to all of them.
6. Add **Installation Instructions** section to the top of the notebook (after "Table of content") and to the corresponding `README.md` file in the notebook directory. See existing notebooks for the reference.
7. Add Scarf Pixel tag for analytics to the notebook (at the end of the first cell) and to the corresponding `README.md` file (to the end of the file). Add relative path to the notebook or `README.md` file as `path` URL query parameter. Example: `<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=5b5a4db0-7875-4bfb-bdbd-01698b5b1a77&file=<RELATIVE_FILE_PATH>" />`. You can use the following command to generate the tag and add it to the file: `python .ci/scarf_pixel.py -s <PATH>`.
8. In case if notebook has specific requirements on python version or OS, it should be noted on top of notebook (before any code blocks) using
8. Add telemetry snippet to the notebook file (e.g. to the cell with fetching notebook_utils file) for tracking notebook execution. Add notebook file name as a parameter to `collect_telemetry()` function. You can use the following command to generate the snippet and add it to the notebook file: `python .ci/telemetry_snippet.py -s <PATH>`. Snippet example:
```python
# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry
from notebook_utils import collect_telemetry
collect_telemetry("<NOTEBOOK_NAME>.ipynb")
```
1. In case if notebook has specific requirements on python version or OS, it should be noted on top of notebook (before any code blocks) using
following colored block:
```
<div class="alert alert-block alert-danger"> <b>Important note:</b> This notebook requires python >= 3.9. Please make sure that your environment fulfill to this requirement before running it </div>
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ List of all notebooks is available in [index file](./notebooks/README.md).
- [To Launch all Notebooks](#to-launch-all-notebooks)
- [🧹 Cleaning Up](#-cleaning-up)
- [⚠️ Troubleshooting](#️-troubleshooting)
- [📊 Telemetry](#-telemetry)
- [📚 Additional Resources](#-additional-resources)
- [🧑‍💻 Contributors](#-contributors)
- [❓ FAQ](#-faq)
Expand Down Expand Up @@ -171,6 +172,30 @@ or create an [issue](https://github.com/openvinotoolkit/openvino_notebooks/issue
- If OpenVINO is installed globally, do not run installation commands in a terminal where `setupvars.bat` or `setupvars.sh` are sourced.
- For Windows installation, it is recommended to use _Command Prompt (`cmd.exe`)_, not _PowerShell_.

[![-----------------------------------------------------](https://user-images.githubusercontent.com/10940214/155750931-fc094349-b6ec-4e1f-9f9a-113e67941119.jpg)]()
<div id='-telemetry'></div>

## 📊 Telemetry

When you execute a notebook cell that contains `collect_telemetry()` function, telemetry data is collected to help us improve your experience.
This data only indicates that the cell was executed and does **not** include any personally identifiable information (PII).

By default, anonymous telemetry data is collected, limited solely to the execution of the notebook.
This telemetry does **not** extend to any Intel software, hardware, websites, or products.

If you prefer to disable telemetry, you can do so at any time by commenting out the specific line responsible for data collection in the notebook:
```python
# collect_telemetry(...)
```
Also you can disable telemetry collection by settting `SCARF_NO_ANALYTICS` or `DO_NOT_TRACK` environment variable to `1`:
```bash
export SCARF_NO_ANALYTICS=1
# or
export DO_NOT_TRACK=1
```

Scarf is used for telemetry purposes. Refer to [Scarf documentation](https://docs.scarf.sh/) to understand how the data is collected and processed.

[![-----------------------------------------------------](https://user-images.githubusercontent.com/10940214/155750931-fc094349-b6ec-4e1f-9f9a-113e67941119.jpg)]()
<div id='-additional-resource'></div>

Expand Down
8 changes: 6 additions & 2 deletions notebooks/hello-detection/hello-detection.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"id": "73d7aedb",
"metadata": {},
"outputs": [],
Expand All @@ -78,7 +78,11 @@
"\n",
"open(\"notebook_utils.py\", \"w\").write(r.text)\n",
"\n",
"from notebook_utils import download_file, device_widget"
"from notebook_utils import download_file, device_widget\n",
"\n",
"# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry\n",
"from notebook_utils import collect_telemetry\n",
"collect_telemetry(\"hello-detection.ipynb\")"
]
},
{
Expand Down
8 changes: 6 additions & 2 deletions notebooks/hello-segmentation/hello-segmentation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"id": "485ef549",
"metadata": {},
"outputs": [],
Expand All @@ -77,7 +77,11 @@
"\n",
"open(\"notebook_utils.py\", \"w\").write(r.text)\n",
"\n",
"from notebook_utils import segmentation_map_to_image, download_file, device_widget"
"from notebook_utils import segmentation_map_to_image, download_file, device_widget\n",
"\n",
"# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry\n",
"from notebook_utils import collect_telemetry\n",
"collect_telemetry(\"hello-segmentation.ipynb\")"
]
},
{
Expand Down
8 changes: 6 additions & 2 deletions notebooks/hello-world/hello-world.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"id": "41ee9436",
"metadata": {},
"outputs": [],
Expand All @@ -77,7 +77,11 @@
"\n",
"open(\"notebook_utils.py\", \"w\").write(r.text)\n",
"\n",
"from notebook_utils import download_file, device_widget"
"from notebook_utils import download_file, device_widget\n",
"\n",
"# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry\n",
"from notebook_utils import collect_telemetry\n",
"collect_telemetry(\"hello-world.ipynb\")"
]
},
{
Expand Down
6 changes: 5 additions & 1 deletion notebooks/object-detection-webcam/object-detection.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@
" url=\"https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/utils/notebook_utils.py\",\n",
")\n",
"\n",
"open(\"notebook_utils.py\", \"w\").write(r.text)"
"open(\"notebook_utils.py\", \"w\").write(r.text)\n",
"\n",
"# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry\n",
"from notebook_utils import collect_telemetry\n",
"collect_telemetry(\"object-detection.ipynb\")"
]
},
{
Expand Down
7 changes: 6 additions & 1 deletion notebooks/pose-estimation-webcam/pose-estimation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@
")\n",
"\n",
"open(\"notebook_utils.py\", \"w\").write(r.text)\n",
"import notebook_utils as utils"
"\n",
"import notebook_utils as utils\n",
"\n",
"# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry\n",
"from notebook_utils import collect_telemetry\n",
"collect_telemetry(\"pose-estimation.ipynb\")"
]
},
{
Expand Down
26 changes: 26 additions & 0 deletions utils/notebook_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,3 +714,29 @@ def optimize_bge_embedding(model_path, output_model_path):
manager.register_pass(ReplaceTensor(packed_layername_tensor_dict_list))
manager.run_passes(ov_model)
ov.save_model(ov_model, output_model_path, compress_to_fp16=False)


def collect_telemetry(file: str = ""):
"""
The function only tracks that the notebooks cell was executed and does not include any personally identifiable information (PII).
"""
try:
import os
import requests
import platform
from pathlib import Path

if os.getenv("SCARF_NO_ANALYTICS") == "1" or os.getenv("DO_NOT_TRACK") == "1":
return
url = "https://openvino.gateway.scarf.sh/telemetry"
params = {
"notebook_dir": Path(__file__).parent.name,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can collect notebook directory assuming that each notebook downloads notebook_utils.py file to the same directory.

"platform": platform.system(),
"arch": platform.machine(),
"python_version": platform.python_version(),
}
if file:
params["file"] = file
requests.get(url, params=params)
except Exception:
pass
Loading