Les citations de motivation étaient à la mode à l'époque où le transfert de MMS et d'e-mails était populaire. Je me souviens que mes parents m'envoyaient au début de chaque matin. Avance rapide jusqu'à aujourd'hui, si vous avez de la chance, vous faites partie d'un groupe de transfert sur l'application de messagerie de votre choix (Whatsapp, Telegram, etc.).
Inspirés par la même idée, nous allons aujourd'hui créer un service qui envoie à nos amis et à notre famille une citation de motivation du jour générée par l'IA. Plutôt que de coder en dur une liste de citations de motivation, nous allons utiliser un modèle d'apprentissage automatique pour générer un devis à la demande afin de ne jamais manquer de citations à partager !
Le modèle OpenAI GPT-2 a été proposé dans Language Models are Unsupervised Multitask Learners par Alec Radford, Jeffrey Wu, Rewon Child, David Luan, Dario Amodei et Ilya Sutskever. Il s'agit d'un transformateur causal pré-formé à l'aide de la modélisation du langage sur un très grand corpus d'environ 40 Go de données textuelles.
Pour simplifier cela, à un niveau élevé, OpenAI GPT2 est un grand modèle de langage qui a été formé sur d'énormes quantités de données. Ce modèle peut être utilisé pour prédire le jeton suivant dans une séquence donnée.
Si cela semble trop compliqué, ne vous inquiétez pas, vous n'avez pas besoin de connaître l'apprentissage automatique ou l'IA pour suivre ce projet. Les bibliothèques telles que
Nous utiliserons le
Heureusement, dans notre cas, il existe un modèle affiné qui a été formé sur l'ensemble de données de 500 000 cotations :
Avec Hugging Face, utiliser ce modèle est aussi simple que de créer un tokenizer
from transformers import AutoTokenizer, AutoModelWithLMHead, pipeline tokenizer = AutoTokenizer.from_pretrained("nandinib1999/quote-generator")
puis construction d'un modèle à partir du modèle pré-entraîné
model = AutoModelWithLMHead.from_pretrained("nandinib1999/quote-generator")
et enfin, construire le générateur que nous pouvons utiliser pour générer le devis
generator = pipeline("text-generation", model=model, tokenizer=tokenizer) # use a starting prompt generator("Keep an open mind and") [{'generated_text': 'Keep an open mind and a deep love for others'}]
Maintenant que nous avons un moyen de générer des devis pour nous, nous devons réfléchir à la manière dont nous pouvons l'utiliser dans notre application. Il existe plusieurs façons de construire cela.
Un avantage clé de la deuxième option est qu'une fois le modèle chargé, l'API peut nous répondre rapidement et peut également être utilisée dans d'autres applications. FWIW, la première option est également une approche tout à fait valable.
Nous pouvons utiliser __ API rapide __ pour créer une API de service rapide. Voici à quoi ça ressemble
# in file api.py from pydantic import BaseModel from fastapi import FastAPI, HTTPException from transformers import AutoTokenizer, AutoModelWithLMHead, pipeline ## create the pipeline tokenizer = AutoTokenizer.from_pretrained("nandinib1999/quote-generator") model = AutoModelWithLMHead.from_pretrained("nandinib1999/quote-generator") generator = pipeline("text-generation", model=model, tokenizer=tokenizer) app = FastAPI() class QuoteRequest(BaseModel): text: str class QuoteResponse(BaseModel): text: str ### Serves the Model API to generate quote @app.post("/generate", response_model=QuoteResponse) async def generate(request: QuoteRequest): resp = generator(request.text) if not resp[0] and not resp[0]["generated_text"]: raise HTTPException(status_code=500, detail='Error in generation') return QuoteResponse(text=resp[0]["generated_text"])
Testons-le
$ uvicorn api:app INFO: Started server process [40767] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Nous pouvons maintenant commencer à envoyer des demandes au point de terminaison /generate
qui générera un devis pour nous.
Maintenant que nous avons un moyen de générer des devis à la demande, nous pouvons nous arrêter ici et commencer à travailler sur l'envoi via
Compte tenu de notre API, nous pouvons maintenant faire ce qui suit pour générer un devis
from random import choice # feel free to add more starting prompts for more variety canned_seeds = ["Always remember to", "Start today with", "It is okay to"] seed = choice(canned_seeds) resp = requests.post('http://127.0.0.1:8000/generate', data=json.dumps({"text": seed})) return resp.json()["text"]
Le premier défi consiste à obtenir une belle image de fond pour notre devis. Pour cela, nous utiliserons l'API Unsplash qui fournit un bon point de terminaison pour renvoyer une image aléatoire correspondant à une requête. Ouverture
Pour garder les choses intéressantes, nous pouvons utiliser différents termes de requête tels que des étoiles, etc. Voici à quoi ressemble le code pour télécharger notre image d'arrière-plan -
from random import choice image_backgdrops = ['nature', 'stars', 'mountains', 'landscape'] backdrop = choice(image_backdrops) response = requests.get("https://source.unsplash.com/random/800×800/?"+ backdrop, stream=True) # write the output the img.png on our filesystem with open('img.png', 'wb') as out_file: shutil.copyfileobj(response.raw, out_file) del response
Ok, maintenant nous avons notre image de fond et un devis ce qui signifie que nous pouvons travailler sur l'assemblage de l'image finale qui sera envoyée aux destinataires. À un niveau élevé, nous voulons placer du texte sur une image, mais même cette tâche simple peut être difficile. Pour commencer, il y a un certain nombre de questions auxquelles nous devons répondre
Les réponses à certaines de ces questions sont plus compliquées que d'autres. Pour rester simple, nous allons placer le texte au centre et faire un peu d'habillage pour qu'il soit beau. Enfin, nous utiliserons un texte de couleur claire pour l'instant. Pour toutes les manipulations d'images, nous utiliserons Python Image Library (PIL) pour nous faciliter la tâche.
# use the image we downloaded in the above step img = Image.open("img.png") width, height = img.size image_editable = ImageDraw.Draw(img) # wrap text lines = textwrap.wrap(text, width=40) # get the line count and generate a starting offset on y-axis line_count = len(lines) y_offset = height/2 - (line_count/2 * title_font.getbbox(lines[0])[3]) # for each line of text, we generate a (x,y) to calculate the positioning for line in lines: (_, _, line_w, line_h) = title_font.getbbox(line) x = (width - line_w)/2 image_editable.text((x,y_offset), line, (237, 230, 211), font=title_font) y_offset += line_h img.save("result.jpg") print("generated " + filename) return filename
Cela génère l'image finale appelée result.jpg
Pour l'avant-dernière étape, nous devons télécharger l'image afin de pouvoir l'utiliser avec Courier. Dans ce cas, j'utilise Firebase Storage mais vous pouvez vous sentir libre d'utiliser ce que vous voulez.
import firebase_admin from firebase_admin import credentials from firebase_admin import storage cred = credentials.Certificate('serviceaccount.json') firebase_admin.initialize_app(cred, {...}) bucket = storage.bucket() blob = bucket.blob(filename) blob.upload_from_filename(filename) blob.make_public() return blob.public_url
Enfin, nous avons tout ce dont nous avons besoin pour commencer à envoyer nos superbes citations à nos amis et à notre famille. Nous pouvons utiliser Courier pour créer un beau modèle d'e-mail.
Envoyer un message avec Courier est aussi simple que possible. Alors que Courier a ses propres SDK qui peuvent faciliter l'intégration, je préfère utiliser son point de terminaison API pour garder les choses simples. Avec mes AUTH_TOKEN
et TEMPLATE_ID
en main, nous pouvons utiliser le morceau de code suivant pour envoyer notre image
import requests headers = { "Accept": "application/json", "Content-Type": "application/json", "Authorization": "Bearer {}".format(os.environ['COURIER_AUTH_TOKEN']) } message={ "to": { "email": os.environ["COURIER_RECIPIENT"] }, "data": { "date": datetime.today().strftime("%B %d, %Y"), "img": image_url ## this is image url we generated earlier }, "routing": { "method": "single", "channels": [ "email" ] }, "template": os.environ["COURIER_TEMPLATE"] } requests.post("https://api.courier.com/send", json={"message": message}, headers=headers)
La clé API se trouve dans
Ce didacticiel a démontré à quel point il est facile de démarrer avec l'apprentissage automatique et Courier.
Si vous voulez aller de l'avant et améliorer ce projet, voici quelques idées intéressantes à essayer