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

МЕНЮ


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

ТЕМЫ


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

Авторизация



Привет, Хаброжители! Эта книга Ноя Гифта предназначена для всех, кого интересуют ИИ, машинное обучение, облачные вычисления, а также любое сочетание данных тем. Как программисты, так и просто неравнодушные технари найдут тут для себя полезную информацию. Примеры кода даны на 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% от стоимости книги пойдет на перевод новых компьютерных книг, список сданных в типографию книг здесь.


Телеграм: t.me/ainewsline

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

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