Книга «Прагматичный ИИ. Машинное обучение и облачные технологии»

МЕНЮ


Искусственный интеллект
Поиск
Регистрация на сайте
Помощь проекту

ТЕМЫ


Новости ИИРазработка ИИВнедрение ИИРабота разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика

Авторизация



RSS


RSS новости


Привет, Хаброжители! Эта книга Ноя Гифта предназначена для всех, кого интересуют ИИ, машинное обучение, облачные вычисления, а также любое сочетание данных тем. Как программисты, так и просто неравнодушные технари найдут тут для себя полезную информацию. Примеры кода даны на Python. Здесь рассматривается множество столь продвинутых тем, как использование облачных платформ (например, AWS, GCP и Azure), а также приемы машинного обучения и реализация ИИ. Джедаи, свободно ориентирующиеся в Python, облачных вычислениях и ML, также найдут для себя много полезных идей, которые смогут сразу применить в своей текущей работе. Предлагаем ознакомиться с отрывком из книги «Создание интеллектуального бота Slack в AWS»
Люди давно мечтают создать «искусственную жизнь». Чаще всего пока это возможно путем создания ботов. Боты становятся все более неотъемлемой частью нашей повседневной жизни, особенно после появления Siri от компании Apple и Alexa от Amazon. В этой главе мы раскроем все тайны создания ботов.

Создание бота

Для создания бота мы воспользуемся библиотекой Slack для языка Python (https://github.com/slackapi/python-slackclient). Для начала работы со Slack необходимо сгенерировать идентификационный маркер. В целом имеет смысл при работе с подобными маркерами экспортировать переменную среды. Я часто делаю это в virtualenv, получая, таким образом, автоматически доступ к ней при выполнении в текущей среде. Для этого необходимо немного «взломать» утилиту virtualenv, отредактировав сценарий activate.

При экспорте переменной Slack в сценарии ~/.env/bin/activate он будет иметь нижеприведенный вид.

И просто для информации, если вы хотите идти в ногу с последними новинками, рекомендуется использовать появившуюся на рынке новую, официальную утилиту Python для управления средой — pipenv (https://github.com/pypa/pipenv):

_OLD_VIRTUAL_PATH="$PATH" PATH="$VIRTUAL_ENV/bin:$PATH" export PATH SLACK_API_TOKEN=<Your Token Here> export SLACK_API_TOKEN

Для проверки того, задано ли значение переменной среды, удобно использовать команду printenv операционных систем OS X и Linux. После этого для проверки отправки сообщения можно воспользоваться следующим коротким сценарием:

import os from slackclient import SlackClient  slack_token = os.environ["SLACK_API_TOKEN"] sc = SlackClient(slack_token)  sc.api_call(    "chat.postMessage",    channel="#general",    text="Hello from my bot! :tada:" )

Стоит также отметить, что утилита pipenv — рекомендуемое решение, объединяющее в одном компоненте возможности утилит pip и virtualenv. Она стала новым стандартом, так что имеет смысл взглянуть на нее с точки зрения управления пакетами.

Преобразование библиотеки в утилиту командной строки

Как и в других примерах из этой книги, удачной идеей будет преобразовать наш код в утилиту командной строки, чтобы облегчить проверку новых идей. Стоит отметить, что многие разработчики-новички часто отдают предпочтение не утилитам командной строки, а другим решениям, например, просто работают в блокнотах Jupiter. Сыграю ненадолго роль адвоката дьявола и задам вопрос, который вполне может возникнуть у читателей: «А зачем нам утилиты командной строки в проекте, основанном на блокнотах Jupiter? Разве смысл блокнотов Jupiter состоит не в том, чтобы сделать ненужными командную оболочку и командную строку?» Добавление утилиты командной строки в проект хорошо тем, что позволяет быстро пробовать различные варианты входных данных. Блоки кода блокнотов Jupiter не принимают входные данные, в некотором смысле это сценарии с жестко «зашитыми» данными.

Множество утилит командной строки на платформах как GCP, так и AWS существует не случайно: они обеспечивают гибкость и возможности, недоступные для графических интерфейсов. Замечательный сборник эссе на эту тему фантаста Нила Стивенсона (Neal Stephenson) называется «В начале… была командная строка». В нем Стивенсон говорит: «GUI приводят к значительным дополнительным накладным расходам на каждый, даже самый маленький компонент программного обеспечения, которые полностью меняют среду программирования». Он заканчивает сборник словами: «… жизнь — штука очень тяжелая и сложная; никакой интерфейс это не изменит; и всякий, кто считает иначе, — простофиля...» Достаточно жестко, но мой опыт подсказывает, что и достаточно правдиво. Жизнь с командной строкой становится лучше. Попробуйте ее — и вы не захотите возвращаться обратно к GUI.

Для этого мы воспользуемся пакетом click, как показано ниже. Отправка сообщений с помощью нового интерфейса оказывается очень простым делом.

./clibot.py send --message "from cli" sending message from cli to #general

Рисунок 7.1 демонстрирует значения по умолчанию, а также настраиваемое сообщение от утилиты cli.

#!/usr/bin/env python import os import click from slackclient import SlackClient  SLACK_TOKEN = os.environ["SLACK_API_TOKEN"]  def send_message(channel="#general",                             message="Hello from my bot!"):      """Отправить сообщение на канал"""       slack_client = SlackClient(SLACK_TOKEN)      res = slack_client.api_call(      "chat.postMessage",      channel=channel,      text=message   )   return res  @click.group() @click.version_option("0.1") def cli():    """   Утилита командной строки для слабаков   """  @cli.command("send") @click.option("--message", default="Hello from my bot!",                        help="text of message") @click.option("--channel", default="#general",                        help="general channel") def send(channel, message):      click.echo(f"sending message {message} to {channel}")      send_message(channel, message=message)  if __name__ == '__main__':      cli()

image

Выводим бот на новый уровень с помощью сервиса AWS Step Functions

После создания каналов связи для отправки сообщений в Slack можно усовершенствовать наш код, а именно: запускать его по расписанию и использовать для каких-либо полезных действий. Сервис пошаговых функций AWS (AWS Step Functions) замечательно подходит для этой цели. В следующем разделе наш бот Slack научится производить скрапинг спортивных страниц Yahoo! игроков НБА, извлекать их места рождения, а затем отправлять эти данные в Slack.

Рисунок 7.2 демонстрирует готовую пошаговую функцию в действии. Первый шаг состоит в извлечении URL профилей игроков НБА, а второй — в использовании библиотеки Beautiful Soup для поиска места рождения каждого из игроков. По завершении выполнения пошаговой функции результаты будут отправлены обратно в Slack.

image
Для координации отдельных частей работы внутри пошаговой функции можно применить AWS Lambda и Chalice. Lambda (https://aws.amazon.com/lambda/) позволяет пользователю выполнять функции в AWS, а фреймворк Chalice (http://chalice.readthedocs.io/en/latest/) дает возможность создания бессерверных приложений на языке Python. Вот некоторые предварительные требования:
  • у пользователя должна быть учетная запись AWS;
  • пользователю необходимы учетные данные для использования API;
  • у роли Lambda (создаваемой Chalice) должна быть политика с привилегиями, необходимыми для вызова соответствующих сервисов AWS, например S3.

Настройка учетных данных IAM

Подробные инструкции по настройке учетных данных AWS можно найти по адресу boto3.readthedocs.io/en/latest/guide/configuration.html. Информацию об экспорте переменных AWS в операционных системах Windows и Linux можно найти здесь. Существует множество способов настройки учетных данных, но пользователи virtualenv могут поместить учетные данные AWS в локальную виртуальную среду, в сценарий /bin/activate:

#Добавляем ключи AWS AWS_DEFAULT_REGION=us-east-1 AWS_ACCESS_KEY_ID=xxxxxxxx AWS_SESSION_TOKEN=xxxxxxxx


#Экспортируем ключи export AWS_DEFAULT_REGION export AWS_ACCESS_KEY_ID export AWS_DEFAULT_REGION

Работа с Chalice. У Chalice есть утилита командной строки с множеством доступных команд:

Usage: chalice [OPTIONS] COMMAND [ARGS]...  Options:     --version                        Show the version and exit.     --project-dir                   TEXT The project directory. Defaults to CWD     --debug / --no-debug      Print debug logs to stderr.     --help                            Show this message and exit.  Commands:     delete     deploy     gen-policy     generate-pipeline Generate a cloudformation template for a...     generate-sdk     local     logs     new-project     package     url

Код внутри шаблона app.py можно заменить на функции сервиса Lambda. В AWS Chalice удобно то, что он дает возможность создавать, помимо веб-сервисов, «автономные» функции Lambda. Благодаря этой функциональности можно создать несколько функций Lambda, связать их с пошаговой функцией и свести воедино, как кубики «Лего».

Например, можно легко создать запускаемую по расписанию функцию Lambda, которая будет выполнять какие-либо действия:

@app.schedule(Rate(1, unit=Rate.MINUTES)) def every_minute(event):       """Событие, запланированное для ежеминутного выполнения"""        #Отправка сообщения боту Slack

Для налаживания взаимодействия с ботом для веб-скрапинга необходимо создать несколько функций. В начале файла находятся импорты и объявлено некоторое количество переменных:

import logging import csv from io import StringIO  import boto3 from bs4 import BeautifulSoup import requests from chalice import (Chalice, Rate)  APP_NAME = 'scrape-yahoo' app = Chalice(app_name=APP_NAME) app.log.setLevel(logging.DEBUG)

Боту может понадобиться хранить часть данных в S3. Следующая функция использует Boto для сохранения результатов в CSV-файле:

def create_s3_file(data, name="birthplaces.csv"):        csv_buffer = StringIO()       app.log.info(f"Creating file with {data} for name")       writer = csv.writer(csv_buffer)       for key, value in data.items():            writer.writerow([key,value])       s3 = boto3.resource('s3')       res = s3.Bucket('aiwebscraping').             put_object(Key=name, Body=csv_buffer.getvalue())       return res

Функция fetch_page использует библиотеку Beautiful Soup для синтаксического разбора HTML-страницы, расположенной в соответствии с URL статистики НБА, и возвращает объект soup:
def fetch_page(url="https://sports.yahoo.com/nba/stats/"):       """Извлекает URL Yahoo"""        #Скачивает страницу и преобразует ее в объект       # библиотеки Beautiful Soup       app.log.info(f"Fetching urls from {url}")       res = requests.get(url)       soup = BeautifulSoup(res.content, 'html.parser')       return soup

Функции get_player_links и fetch_player_urls получают ссылки на URL профилей игроков:

def get_player_links(soup):       """Получает ссылки из URL игроков        Находит все URL на странице в тегах 'a' и фильтрует их в поисках       строки 'nba/players'       """        nba_player_urls = []       for link in soup.find_all('a'):            link_url = link.get('href')            #Отбрасываем неподходящие            if link_url:                if "nba/players" in link_url:                    print(link_url)                    nba_player_urls.append(link_url)       return nba_player_urls   def fetch_player_urls():       """Возвращает URL игроков"""       soup = fetch_page()       urls = get_player_links(soup)       return urls

Далее в функции find_birthplaces мы извлекаем с расположенных по этим URL страниц места рождения игроков:

def find_birthplaces(urls):       """Получаем места рождения со страниц профилей игроков NBA           на Yahoo"""        birthplaces = {}       for url in urls:            profile = requests.get(url)            profile_url = BeautifulSoup(profile.content, 'html.parser')            lines = profile_url.text            res2 = lines.split(",")            key_line = []            for line in res2:                 if "Birth" in line:                     #print(line)                     key_line.append(line)            try:                 birth_place = key_line[0].split(":")[-1].strip()                 app.log.info(f"birth_place: {birth_place}")            except IndexError:                 app.log.info(f"skipping {url}")                 continue            birthplaces[url] = birth_place            app.log.info(birth_place)       return birthplaces

Теперь мы перейдем к функциям Chalice. Обратите внимание: для фреймворка Chalice необходимо, чтобы был создан путь по умолчанию:

#Их можно вызвать с помощью HTTP-запросов @app.route('/') def index():       """Корневой URL"""        app.log.info(f"/ Route: for {APP_NAME}")       return {'app_name': APP_NAME}

Следующая функция Lambda представляет собой маршрут, связывающий HTTP URL с написанной ранее функцией:

@app.route('/player_urls') def player_urls():       """Извлекает URL игроков"""        app.log.info(f"/player_urls Route: for {APP_NAME}")       urls = fetch_player_urls()       return {"nba_player_urls": urls}

Следующие функции Lambda — автономные, их можно вызвать внутри пошаговой функции:

#Это автономная функция Lambda @app.lambda_function() def return_player_urls(event, context):      """Автономная функция Lambda, возвращающая URL игроков"""       app.log.info(f"standalone lambda 'return_players_urls'         {APP_NAME} with {event} and {context}")      urls = fetch_player_urls()      return {"urls": urls}  #Это автономная функция Lambda @app.lambda_function() def birthplace_from_urls(event, context):       """Находит места рождения игроков"""        app.log.info(f"standalone lambda 'birthplace_from_urls'          {APP_NAME} with {event} and {context}")       payload = event["urls"]       birthplaces = find_birthplaces(payload)       return birthplaces  #Это автономная функция Lambda @app.lambda_function() def create_s3_file_from_json(event, context):       """Создает файл S3 на основе данных в формате JSON"""        app.log.info(f"Creating s3 file with event data {event}           and context {context}")       print(type(event))       res = create_s3_file(data=event)       app.log.info(f"response of putting file: {res}")       return True

Если запустить получившееся приложение Chalice локально, будут выведены следующие результаты:

? scrape-yahoo git:(master) ? chalice local Serving on 127.0.0.1:8000 scrape-yahoo - INFO - / Route: for scrape-yahoo 127.0.0.1 - - [12/Dec/2017 03:25:42] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [12/Dec/2017 03:25:42] "GET /favicon.ico" scrape-yahoo - INFO - / Route: for scrape-yahoo 127.0.0.1 - - [12/Dec/2017 03:25:45] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [12/Dec/2017 03:25:45] "GET /favicon.ico" scrape-yahoo - INFO - /player_urls Route: for scrape-yahoo scrape-yahoo - INFO - https://sports.yahoo.com/nba/stats/ https://sports.yahoo.com/nba/players/4563/ https://sports.yahoo.com/nba/players/5185/ https://sports.yahoo.com/nba/players/3704/ https://sports.yahoo.com/nba/players/5012/ https://sports.yahoo.com/nba/players/4612/ https://sports.yahoo.com/nba/players/5015/ https://sports.yahoo.com/nba/players/4497/ https://sports.yahoo.com/nba/players/4720/ https://sports.yahoo.com/nba/players/3818/ https://sports.yahoo.com/nba/players/5432/ https://sports.yahoo.com/nba/players/5471/ https://sports.yahoo.com/nba/players/4244/ https://sports.yahoo.com/nba/players/5464/ https://sports.yahoo.com/nba/players/5294/ https://sports.yahoo.com/nba/players/5336/ https://sports.yahoo.com/nba/players/4390/ https://sports.yahoo.com/nba/players/4563/ https://sports.yahoo.com/nba/players/3704/ https://sports.yahoo.com/nba/players/5600/ https://sports.yahoo.com/nba/players/4624/ 127.0.0.1 - - [12/Dec/2017 03:25:53] "GET /player_urls" 127.0.0.1 - - [12/Dec/2017 03:25:53] "GET /favicon.ico"

Для развертывания приложения выполните команду chalice deploy:

? scrape-yahoo git:(master) ? chalice deploy Creating role: scrape-yahoo-dev Creating deployment package. Creating lambda function: scrape-yahoo-dev Initiating first time deployment. Deploying to API Gateway stage: api https://bt98uzs1cc.execute-api.us-east-1.amazonaws.com/api/

Благодаря интерфейсу командной строки для HTTP (https://github.com/jakubroztocil/httpie) мы вызываем маршрут HTTP из AWS и извлекаем доступные в /api/player_urls ссылки:

? scrape-yahoo git:(master) ? http  https://<a lambda route>.amazonaws.com/api/player_urls HTTP/1.1 200 OK Connection: keep-alive Content-Length: 941 Content-Type: application/json Date: Tue, 12 Dec 2017 11:48:41 GMT Via: 1.1 ba90f9bd20de9ac04075a8309c165ab1.cloudfront.net (CloudFront) X-Amz-Cf-Id: ViZswjo4UeHYwrc9e-5vMVTDhV_Ic0dhVIG0BrDdtYqd5KWcAuZKKQ== X-Amzn-Trace-Id: sampled=0;root=1-5a2fc217-07cc12d50a4d38a59a688f5c X-Cache: Miss from cloudfront x-amzn-RequestId: 64f24fcd-df32-11e7-a81a-2b511652b4f6  {         "nba_player_urls": [               "https://sports.yahoo.com/nba/players/4563/",               "https://sports.yahoo.com/nba/players/5185/",               "https://sports.yahoo.com/nba/players/3704/",               "https://sports.yahoo.com/nba/players/5012/",               "https://sports.yahoo.com/nba/players/4612/",               "https://sports.yahoo.com/nba/players/5015/",               "https://sports.yahoo.com/nba/players/4497/",               "https://sports.yahoo.com/nba/players/4720/",               "https://sports.yahoo.com/nba/players/3818/",               "https://sports.yahoo.com/nba/players/5432/",               "https://sports.yahoo.com/nba/players/5471/",               "https://sports.yahoo.com/nba/players/4244/",               "https://sports.yahoo.com/nba/players/5464/",               "https://sports.yahoo.com/nba/players/5294/",               "https://sports.yahoo.com/nba/players/5336/",               "https://sports.yahoo.com/nba/players/4390/",               "https://sports.yahoo.com/nba/players/4563/",               "https://sports.yahoo.com/nba/players/3704/",               "https://sports.yahoo.com/nba/players/5600/",               "https://sports.yahoo.com/nba/players/4624/"        ] }

Еще один удобный способ работы с функциями Lambda — непосредственный их вызов с помощью пакета click и библиотеки Boto языка Python.

Мы можем создать новую утилиту командной строки с названием wscli.py (сокращение от web-scraping command-line interface — «интерфейс командной строки для веб-скрапинга»). В первой части кода мы настраиваем журналирование и импортируем библиотеки:

#!/usr/bin/env python  import logging import json  import boto3 import click from pythonjsonlogger import jsonlogger  #Инициализация журналирования log = logging.getLogger(__name__) log.setLevel(logging.INFO) LOGHANDLER = logging.StreamHandler() FORMMATTER = jsonlogger.JsonFormatter() LOGHANDLER.setFormatter(FORMMATTER) log.addHandler(LOGHANDLER)

Следующие три функции предназначены для подключения к функции Lambda через invoke_lambda:

###Вызовы API Boto Lambda def lambda_connection(region_name="us-east-1"):       """Создаем подключение к Lambda"""        lambda_conn = boto3.client("lambda", region_name=region_name)       extra_msg = {"region_name": region_name, "aws_service": "lambda"}       log.info("instantiate lambda client", extra=extra_msg)       return lambda_conn  def parse_lambda_result(response):       """Получаем результаты из ответа библиотеки Boto в формате JSON"""              body = response['Payload']       json_result = body.read()       lambda_return_value = json.loads(json_result)       return lambda_return_value  def invoke_lambda(func_name, lambda_conn, payload=None,                              invocation_type="RequestResponse"):       """Вызываем функцию Lambda"""         extra_msg = {"function_name": func_name, "aws_service": "lambda",                            "payload":payload}       log.info("Calling lambda function", extra=extra_msg)       if not payload:            payload = json.dumps({"payload":"None"})        response = lambda_conn.invoke(FunctionName=func_name,                        InvocationType=invocation_type,                        Payload=payload       )       log.info(response, extra=extra_msg)       lambda_return_value = parse_lambda_result(response)       return lambda_return_value

Обертываем функцию invoke_lambda с помощью пакета Python для создания утилит командной строки Click. Обратите внимание, что мы задали значение по умолчанию для опции --func, при котором используется развернутая нами ранее функция Lambda:

@click.group() @click.version_option("1.0") def cli():       """Вспомогательная утилита командной строки для веб-скрапинга"""  @cli.command("lambda") @click.option("--func",             default="scrape-yahoo-dev-return_player_urls",             help="name of execution") @click.option("--payload", default='{"cli":"invoke"}',             help="name of payload") def call_lambda(func, payload):        """Вызывает функцию Lambda         ./wscli.py lambda        """        click.echo(click.style("Lambda Function invoked from cli:",              bg='blue', fg='white'))        conn = lambda_connection()        lambda_return_value = invoke_lambda(func_name=func,                lambda_conn=conn,                payload=payload)        formatted_json = json.dumps(lambda_return_value,                sort_keys=True, indent=4)        click.echo(click.style(             "Lambda Return Value Below:", bg='blue', fg='white'))        click.echo(click.style(formatted_json,fg="red"))  if __name__ == "__main__":      cli()

Выводимые этой утилитой результаты аналогичны вызову HTTP-интерфейса:

? X ./wscli.py lambda  --func=scrape-yahoo-dev-birthplace_from_urls --payload '{"url":["https://sports.yahoo.com/nba/players/4624/", "https://sports.yahoo.com/nba/players/5185/"]}' Lambda Function invoked from cli: {"message": "instantiate lambda client", "region_name": "us-east-1", "aws_service": "lambda"} {"message": "Calling lambda function", "function_name": "scrape-yahoo-dev-birthplace_from_urls", "aws_service": "lambda", "payload": "{"url":["https://sports.yahoo.com/nba/players/4624/", "https://sports.yahoo.com/nba/players/5185/"]}"} {"message": null, "ResponseMetadata": {"RequestId": "a6049115-df59-11e7-935d-bb1de9c0649d", "HTTPStatusCode": 200, "HTTPHeaders": {"date": "Tue, 12 Dec 2017 16:29:43 GMT", "content-type": "application/json", "content-length": "118", "connection": "keep-alive", "x-amzn-requestid": "a6049115-df59-11e7-935d-bb1de9c0649d", "x-amzn-remapped-content-length": "0", "x-amz-executed-version": "$LATEST", "x-amzn-trace-id": "root=1-5a3003f2-2583679b2456022568ed0682;sampled=0"}, "RetryAttempts": 0}, "StatusCode": 200, "ExecutedVersion": "$LATEST", "Payload": "<botocore.response.StreamingBody object at 0x10ee37dd8>", "function_name": "scrape-yahoo-dev-birthplace_from_urls", "aws_service": "lambda", "payload": "{"url":["https://sports.yahoo.com/nba/players/4624/", "https://sports.yahoo.com/nba/players/5185/"]}"} Lambda Return Value Below: {         "https://sports.yahoo.com/nba/players/4624/": "Indianapolis",         "https://sports.yahoo.com/nba/players/5185/": "Athens" }

Завершение создания пошаговой функции

Последний этап создания пошаговой функции, как описывается в документации от AWS (https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-creating-activity-state-machine.html), — создание с помощью веб-интерфейса структуры конечного автомата в формате нотации объектов JavaScript (JavaScript Object Notation, JSON). Следующий код демонстрирует этот конвейер, начиная от исходных функций Lambda для скрапинга Yahoo!, сохранения данных в файле S3 и, наконец, отправки содержимого в Slack:

{       "Comment": "Fetch Player Urls",       "StartAt": "FetchUrls",       "States": {          "FetchUrls": {              "Type": "Task",              "Resource":               "arn:aws:lambda:us-east-1:561744971673:              function:scrape-yahoo-dev-return_player_urls",              "Next": "FetchBirthplaces"          },          "FetchBirthplaces": {              "Type": "Task",              "Resource":               "arn:aws:lambda:us-east-1:561744971673:              function:scrape-yahoo-dev-birthplace_from_urls",              "Next": "WriteToS3"          },           "WriteToS3": {              "Type": "Task",              "Resource": "arn:aws:lambda:us-east-1:              561744971673:function:scrape-yahoo-dev-create_s3_file_from_json",              "Next": "SendToSlack"          },          "SendToSlack": {              "Type": "Task",              "Resource": "arn:aws:lambda:us-east-1:561744971673:              function:send_message",              "Next": "Finish"          },               "Finish": {              "Type": "Pass",              "Result": "Finished",              "End": true           }      } }

На рис. 7.2 было показано выполнение первой части этого конвейера. Чрезвычайно полезна возможность видеть промежуточные результаты работы конечного автомата. Кроме того, возможность мониторинга в режиме реального времени каждой части конечного автомата очень удобна для отладки.

Рисунок 7.3 демонстрирует полный конвейер с добавлением шагов записи в S3-файл и отправки содержимого в Slack. Осталось только решить, как запускать эту утилиту скрапинга — через определенный интервал времени или в ответ на какое-либо событие.

image

Резюме

В этой главе вы познакомились с множеством потрясающих концепций построения приложений ИИ. В ней были созданы бот Slack и утилита веб-скрапинга, соединенные затем с помощью бессерверных сервисов от AWS. В такой начальный каркас можно добавить еще много всего — например, Lambda-функцию обработки написанных на естественных языках текстов для чтения веб-страниц и получения их краткого содержимого или алгоритм кластеризации без учителя, который бы кластеризовал новых игроков НБА по произвольным атрибутам.

» Более подробно с книгой можно ознакомиться на сайте издательства » Оглавление » Отрывок Для Хаброжителей скидка 20% по купону — Гифт

P.S.: 7% от стоимости книги пойдет на перевод новых компьютерных книг, список сданных в типографию книг здесь.


Источник: habr.com

Комментарии: