Skip to content

Commit

Permalink
CICD : IFrame management (ia-z#73)
Browse files Browse the repository at this point in the history
* feat: creation d'un dossier dedié au module 1

* feat: ajout de tous les chapitres actuels du module 1 dans un dossier dédié, modif du _toc pour en faire une section

* feat: re-enumeration des chapitres

* fix: typos

* fix: renomme les chapitres avec deux chiffres par numéros

* feat: réécriture du chapitre 3

* feat: début chap 3 OK + sauvegarde gradient descent

* feat: fin du chapitre 3!

* feat: les sources sont proprement affichées

* feat: plotly support and plotly figures for chap 3

* feat: now delete old iframes before generating the new one during compilation

* [CICD] Add copy iframes step to pipeline

* Fix: call python script correctly

* Fix : copy iframes using right versions of dependencies

* IAZLogger for DevOps scripting

Co-authored-by: PierrotLC <[email protected]>
Co-authored-by: Pierre Pereira <[email protected]>
Co-authored-by: Lucas Pauzies <[email protected]>
  • Loading branch information
4 people authored Jun 21, 2022
1 parent b7cefe5 commit 1ad50e1
Show file tree
Hide file tree
Showing 27 changed files with 1,369 additions and 1,338 deletions.
70 changes: 70 additions & 0 deletions .github/scripts/copy_iframes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import os
import shutil
import logging
from argparse import ArgumentParser
from typing import Callable
from utils.iaz_logger import IAZLogger

# Logger setup
logger = IAZLogger()

# Script constants
IFRAMES_FOLDER = "iframe_figures"

def create_parser() -> ArgumentParser:
parser = ArgumentParser()
parser.add_argument("root_directory", help="The root directory where '_build' folder exists as output from 'jupyter-book' build step.")
parser.add_argument("current_directory", help=f"The current directory from where you want to search for '{IFRAMES_FOLDER}' folders recursively.")
return parser

def copy_iframes(current_directory: str, root_directory: str, verbose: bool = True) -> None:
"""Copy iframes from 'current_directory' to build directory of 'jupyter-book' command.
Args:
current_directory (str): Path of the directory which contains a subdirectory `iframe_figures`.
root_directory (str): Path of the root directory, where the website is build.
verbose (bool, optional): Verbose of the function. Defaults to True.
"""
# Let the function raise exceptions if no 'iframe_figures' directory found.
if IFRAMES_FOLDER not in os.listdir(current_directory):
logger.warning("No iframes in %s", current_directory)
return

# Define absolute path of iframes folder as it should be
absolute_current_directory = os.path.abspath(current_directory)
absolute_iframes_folder = os.path.join(absolute_current_directory, IFRAMES_FOLDER)
if verbose: logger.info("Built iframes absolute path : '%s'.", absolute_iframes_folder)
# Define absolute root directory as it should be
absolute_root_directory = os.path.abspath(root_directory)
if verbose: logger.info("Built root absolute path : '%s'.", absolute_root_directory)
# Find common path in absolute directories
common_path = os.path.commonpath([absolute_iframes_folder, absolute_root_directory])
complete_path = absolute_iframes_folder.split(common_path)[-1]
website_path = f"{os.path.join(absolute_root_directory, '_build', 'html')}{complete_path}"
if verbose: logger.info("Define website path where to make the copy : '%s'.", website_path)
logger.info("Copying '%s' to %s", absolute_iframes_folder, website_path)
#shutil.copytree(absolute_iframes_folder, website_path)
logger.info("Copied sucessfully to '%s'.", website_path)

def apply_recursive(current_directory: str, applied_function: Callable[[str], None]) -> None:
"""Check recursively if 'iframe_figures' is in the 'current_directory'.
If so, call the function `applied_function` with the path of the directory containing 'iframe_figures.
If not, call this function recursively on all child directories.
Args:
current_directory (str): Path of the directory where we look for an 'iframe_figures' subdirectory.
applied_function (Callable): Function to call when we find an 'iframe_figures'.
"""
current_directory_subdirectories = [ dirname for dirname in os.listdir(current_directory) if os.path.isdir(os.path.join(current_directory, dirname)) ]
for directory_name in current_directory_subdirectories:
if directory_name == IFRAMES_FOLDER: applied_function(current_directory)
else: apply_recursive(os.path.join(current_directory, directory_name), applied_function)


if __name__ == '__main__':
parser = create_parser()
args = parser.parse_args()
root_directory = args.root_directory
current_directory = args.current_directory
apply_recursive(current_directory, lambda walking_directory: copy_iframes(walking_directory, root_directory))

Empty file.
13 changes: 13 additions & 0 deletions .github/scripts/utils/iaz_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import logging

from colorlog import ColoredFormatter

class IAZLogger(logging.Logger):

def __init__(self, name: str = "IAZ Logger", level: int = logging.INFO) -> None:
super().__init__(name, level)
logger_format = "%(asctime)s [%(levelname)s] %(message)s"
console_handler = logging.StreamHandler()
console_handler.setLevel(level)
console_handler.setFormatter(ColoredFormatter(logger_format, force_color=True))
self.addHandler(console_handler)
3 changes: 3 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
# Build web project using jupyter-book
- name: Build Jupyter-Book
run: jupyter-book build .
# Copy iframes where we want to have iframes
- name: Copy iframes from compiled notebooks to website
run: python .github/scripts/copy_iframes.py . docs/
# Upload the artifact to be used in next job
- uses: actions/upload-artifact@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ _build/
venv/

.DS_Store

# Notebook outputs
**/iframe_figures/
2 changes: 1 addition & 1 deletion _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exclude_patterns: [_build, "**.ipynb_checkpoints", .venv, venv, organisation]
# Force re-execution of notebooks on each build.
# See https://jupyterbook.org/content/execute.html
execute:
execute_notebooks: off
execute_notebooks: auto

# Define the name of the latex output file for PDF builds
latex:
Expand Down
4 changes: 3 additions & 1 deletion _toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ root: README
parts:
- caption: Apprentissage automatique
chapters:
- glob: "docs/Cours fondamentaux ML/*"
- file: "docs/Cours fondamentaux ML/module_1_introduction/01 - Pourquoi le ML & information grâce à la data.md"
sections:
- glob: "docs/Cours fondamentaux ML/module_1_introduction/*"
- caption: Traitement automatique de la langue
chapters:
- glob: "docs/NLP/*"
Expand Down
5 changes: 5 additions & 0 deletions compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#! /usr/bin/bash
rm -rf ./_build
python3 manage_iframes.py delete ./docs/
jupyter-book build .
python3 manage_iframes.py copy ./docs/ .
1,222 changes: 0 additions & 1,222 deletions docs/Cours fondamentaux ML/3 - Regression lineaire.ipynb

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Construire un tel modèle est la partie la plus difficile, et
il est possible de s'y attaquer de plusieurs manières. Mais deux méthodes principales s'imposent:

* Etablir des hypothèses sur la nature de la relation entre l'historique du consommateur et les items potentiels,
définir un ensemble de règles qui vont choisir quels items mettre en avant;
définir un ensemble de règles qui vont choisir quels items mettre en avant.
* Récolter beaucoup de données sous forme de couple `(historique, items achetés)`
et trouver le modèle qui explique le mieux les relations entre les données.

Expand Down Expand Up @@ -96,17 +96,14 @@ L'information qu'elles récupèrent est particulièrement rentable.
**Il y a quand même des considérations éthiques lorsqu'il s'agit de manipuler des données privées.
Nous ne rentrerons pas dans ce sujet, mais vous devriez toujours vous poser ce genre de questions avant de vous lancer dans une exploitation de données.**

## Résumé
Voici la liste des choses à retenir pour ce chapitre:
## Conclusion

* Le ML permet de fabriquer des modèles plus souples, qui ont potentiellement de meilleures performances que ceux des systèmes symboliques;
* Un modèle de ML peut facilement s'adapter à un environnement dynamique;
* Le ML permet de fabriquer des modèles plus souples, qui ont potentiellement de meilleurs performances que ceux des systèmes symboliques.
* Un modèle de ML peut facilement s'adapter à un environnement dynamique.
* Une combinaison entre les méthodes symboliques et automatiques est souvent ce qui donne de meilleurs résultats.

## Sources

- https://karpathy.medium.com/software-2-0-a64152b37c35

- "Comprendre le Machine Learning en 5min" de Defend Intelligence https://www.youtube.com/watch?v=RC7GTAKoFGA

- "Hands-On Machine Learning with Scikit-Learn, Keras & Tensorflow. Concepts, Tools, and Techniques to Build Intelligent Systems" O'Reilly, 2nd Edition, Aurélien Géron
* [Comprendre le Machine Learning en 5min, Defend Intelligence](https://www.youtube.com/watch?v=RC7GTAKoFGA)
* [Machine Learning avec Scikit-Learn, A. Géron](https://www.dunod.com/sciences-techniques/machine-learning-avec-scikit-learn-mise-en-oeuvre-et-cas-concrets-0)
* [Software 2.0, Karpathy](https://karpathy.medium.com/software-2-0-a64152b37c35)
Loading

0 comments on commit 1ad50e1

Please sign in to comment.