{ "cells": [ { "cell_type": "markdown", "id": "d4b9227c", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "93e1226b", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Générer du HTML : solutions\n", "==========================\n", "\n", "**Loïc Grobol** [](mailto:lgrobol@parisnanterre.fr)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "cc93ace3", "metadata": {}, "outputs": [], "source": [ "from IPython.display import display, HTML" ] }, { "cell_type": "markdown", "id": "7bb550ae", "metadata": {}, "source": [ "## 🥋 Exo 🥋\n", "\n", "Concevoir\n", "\n", "> - Une page HTML avec un formulaire comprenant un champ de texte et un bouton de soumission.\n", "> Assurez-vous qu'elle passe au [valideur du W3C](https://validator.w3.org)" ] }, { "cell_type": "markdown", "id": "abff3b00", "metadata": {}, "source": [ "```html\n", "\n", "\n", " \n", " \n", " Envoyer un message\n", " \n", " \n", "
\n", " \n", " \n", " \n", "
\n", " \n", "\n", "```" ] }, { "cell_type": "markdown", "id": "3ab54a62", "metadata": {}, "source": [ "> - Une API avec FastAPI qui reçoit des requêtes de type POST venant de la page que vous avez créé\n", "> et qui crée pour chacune un nouveau fichier texte sur votre machine dont le contenu est le\n", "> contenu du champ de texte. Vous aurez besoin de regarder [dans sa\n", "> doc](https://fastapi.tiangolo.com/tutorial/request-forms/) comment on récupère dans FastAPI des\n", "> données envoyées depuis un formulaire (malheureusement ce n'est pas du JSON ! Pour ça il faut\n", "> court-circuiter avec du JavaScript)." ] }, { "cell_type": "code", "execution_count": null, "id": "7f256d13", "metadata": {}, "outputs": [], "source": [ "# %load examples/html_receiver.py\n", "import itertools\n", "import pathlib\n", "\n", "from fastapi import FastAPI, Form\n", "\n", "\n", "app = FastAPI()\n", "\n", "\n", "@app.post(\"/\")\n", "async def read_message(message: str = Form(...)):\n", " file_number = next(\n", " i for i in itertools.count() if not pathlib.Path(f\"{i}.txt\").exists()\n", " )\n", " pathlib.Path(f\"{file_number}.txt\").write_text(message)\n" ] }, { "cell_type": "markdown", "id": "ec5b6ce3", "metadata": {}, "source": [ "### 🎈 Exo 🎈\n", "\n", "> Écrire une fonction qui prend en argument une liste de chaines de caractères et un chemin vers un\n", "> fichier et qui écrit dans ce fichier une page HTML qui contient une liste non-ordonnée dont les\n", "> éléments sont les chaînes passées en argument." ] }, { "cell_type": "markdown", "id": "e6898242", "metadata": {}, "source": [ "Bien entendu, vérifiez que votre HTML passe au [valideur du W3C](https://validator.w3.org)." ] }, { "cell_type": "code", "execution_count": null, "id": "ee4f5110", "metadata": {}, "outputs": [], "source": [ "def make_ul(elems: List[str], path: str):\n", " above = \"\"\"\n", "\n", " \n", " \n", " What is the Average Flying Speed of an African Sparrow?\n", " \n", " \n", " \n", " \n", "\n", "\"\"\"\n", " lst = \"\\n\".join([f\"
  • {name}
  • \" for name in elems])\n", " content = \"\\n\".join([above, lst, below])\n", " with open(path, \"w\") as out_stream:\n", " out_stream.write(content)\n", "\n", "# Pour tester\n", "make_ul([\"The Beths\", \"Beirut\", \"Death Cab for Cutie\"], \"local/moody_bands.html\")\n", "print(open(\"local/moody_bands.html\").read())" ] }, { "cell_type": "markdown", "id": "6d3dfb72", "metadata": {}, "source": [ "## 🧊 Exo 🧊\n", "\n", "> 1\\. Concevoir une API avec FastAPI qui reçoit des requêtes de type POST contenant une liste de\n", "> chaînes de caractère et répond avec une page HTML qui contient une liste ordonnée dont les\n", "> éléments sont les chaînes de caractères reçus.\n", ">\n", "> Bien entendu, vérifiez que votre HTML passe au [valideur du W3C](https://validator.w3.org)." ] }, { "cell_type": "code", "execution_count": null, "id": "ce1a699a", "metadata": {}, "outputs": [], "source": [ "# %load examples/echo_list_api.py\n", "from typing import List\n", "from fastapi import FastAPI\n", "from pydantic import BaseModel\n", "from fastapi.responses import HTMLResponse\n", "\n", "app = FastAPI()\n", "\n", "\n", "class InputData(BaseModel):\n", " lines: List[str]\n", "\n", "\n", "@app.post(\"/\", response_class=HTMLResponse)\n", "async def display(inpt: InputData):\n", " above = \"\"\"\n", "\n", " \n", " \n", " This is what you asked me to display\n", " \n", " \n", "
      \n", "\"\"\"\n", " below = \"\"\"\n", "
    \n", " \n", "\n", "\"\"\"\n", " lst = \"\\n\".join([f\"
  • {name}
  • \" for name in inpt.lines])\n", " html_content = \"\\n\".join([above, lst, below])\n", " return HTMLResponse(content=html_content, status_code=200)" ] }, { "cell_type": "markdown", "id": "05608963", "metadata": {}, "source": [ "> 2\\. Reprendre votre API précédente qui utilisait spaCy pour renvoyer les POS tag correspondant à\n", "> une requête et faites lui renvoyer une présentation des résultats en HTML plutôt que du JSON." ] }, { "cell_type": "code", "execution_count": null, "id": "d5c094d3", "metadata": {}, "outputs": [], "source": [ "# %load examples/spacy_html_api.py\n", "from fastapi import FastAPI, HTTPException\n", "from pydantic import BaseModel\n", "from fastapi.responses import HTMLResponse\n", "import spacy\n", "\n", "app = FastAPI()\n", "\n", "\n", "class InputData(BaseModel):\n", " sentence: str\n", "\n", "\n", "@app.post(\"/postag\")\n", "async def postag(inpt: InputData, model=\"fr_core_news_sm\"):\n", " if model not in spacy.util.get_installed_models():\n", " raise HTTPException(status_code=422, detail=f\"Model {model!r} unavailable\")\n", " nlp = spacy.load(model)\n", " doc = nlp(inpt.sentence)\n", " above = \"\"\"\n", "\n", " \n", " \n", " This is what you asked me to display\n", " \n", " \n", "
      \n", "\"\"\"\n", " below = \"\"\"\n", "
    \n", " \n", "\n", "\"\"\"\n", " lst = \"\\n\".join([f\"
  • {w.text}: {w.pos_}
  • \" for w in doc])\n", " html_content = \"\\n\".join([above, lst, below])\n", " return HTMLResponse(content=html_content, status_code=200)\n", "\n", "\n", "@app.get(\"/list\")\n", "async def list_models():\n", " return {\"models\": spacy.util.get_installed_models()}" ] }, { "cell_type": "markdown", "id": "1755068e", "metadata": {}, "source": [ "## 🙄 Exo 🙄\n", "\n", "Reprenez les APIs de 🧊 et réécrivez-les en Jinja. Si, si, c'est pour votre bien." ] } ], "metadata": { "jupytext": { "formats": "ipynb,md", "split_at_heading": true }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 5 }