|
@@ -18,21 +18,11 @@
|
|
|
},
|
|
|
{
|
|
|
"cell_type": "code",
|
|
|
- "execution_count": 2,
|
|
|
+ "execution_count": 1,
|
|
|
"metadata": {},
|
|
|
- "outputs": [
|
|
|
- {
|
|
|
- "name": "stderr",
|
|
|
- "output_type": "stream",
|
|
|
- "text": [
|
|
|
- "cloudfoundry-client 0.0.25 has requirement protobuf==2.6.1, but you'll have protobuf 3.6.1 which is incompatible.\n",
|
|
|
- "You are using pip version 10.0.1, however version 18.1 is available.\n",
|
|
|
- "You should consider upgrading via the 'python -m pip install --upgrade pip' command.\n"
|
|
|
- ]
|
|
|
- }
|
|
|
- ],
|
|
|
+ "outputs": [],
|
|
|
"source": [
|
|
|
- "!pip install -q -U Slacker"
|
|
|
+ "!pip install - q - U Slacker"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -41,25 +31,30 @@
|
|
|
"metadata": {},
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
+ "# ALl outputs \n",
|
|
|
+ "from IPython.core.interactiveshell import InteractiveShell\n",
|
|
|
+ "InteractiveShell.ast_node_interactivity = 'all'\n",
|
|
|
+ "\n",
|
|
|
+ "# Slacker\n",
|
|
|
+ "from slacker import Slacker\n",
|
|
|
+ "\n",
|
|
|
+ "# Data manipulation\n",
|
|
|
"import numpy as np\n",
|
|
|
"import pandas as pd\n",
|
|
|
"\n",
|
|
|
"%load_ext autoreload\n",
|
|
|
"%autoreload 2\n",
|
|
|
"\n",
|
|
|
- "# Slacker \n",
|
|
|
- "from slacker import Slacker\n",
|
|
|
+ "\n",
|
|
|
"\n",
|
|
|
"# Visualization\n",
|
|
|
- "import matplotlib.pyplot as plt\n",
|
|
|
"import seaborn as sns\n",
|
|
|
+ "import matplotlib.pyplot as plt\n",
|
|
|
"%matplotlib inline\n",
|
|
|
"plt.style.use('fivethirtyeight')\n",
|
|
|
"\n",
|
|
|
"# Displaying images\n",
|
|
|
- "from IPython.display import Image\n",
|
|
|
- "from IPython.core.interactiveshell import InteractiveShell\n",
|
|
|
- "InteractiveShell.ast_node_interactivity = 'all'"
|
|
|
+ "from IPython.display import Image"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -122,7 +117,8 @@
|
|
|
"# Connect to Slack\n",
|
|
|
"slack = Slacker(slack_api_token)\n",
|
|
|
"if slack.api.test().successful:\n",
|
|
|
- " print(f\"Successfully connected to {slack.team.info().body['team']['name']}.\")\n",
|
|
|
+ " print(\n",
|
|
|
+ " f\"Successfully connected to {slack.team.info().body['team']['name']}.\")\n",
|
|
|
"else:\n",
|
|
|
" print('Try Again!')"
|
|
|
]
|
|
@@ -195,7 +191,7 @@
|
|
|
"source": [
|
|
|
"from IPython.display import Image\n",
|
|
|
"\n",
|
|
|
- "Image(url = 'https://avatars.slack-edge.com/2018-11-30/492734348690_802c4805ab4a0d29383b_230.png')"
|
|
|
+ "Image(url='https://avatars.slack-edge.com/2018-11-30/492734348690_802c4805ab4a0d29383b_230.png')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -266,10 +262,10 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "import warnings\n",
|
|
|
- "warnings.filterwarnings('ignore', category = FutureWarning)\n",
|
|
|
"from utils import get_data_and_model, get_options\n",
|
|
|
- " \n",
|
|
|
+ "import warnings\n",
|
|
|
+ "warnings.filterwarnings('ignore', category=FutureWarning)\n",
|
|
|
+ "\n",
|
|
|
"command_dict = get_options(slack)\n",
|
|
|
"command_dict['functions']['users']\n",
|
|
|
"command_dict['functions']['channels']"
|
|
@@ -319,7 +315,8 @@
|
|
|
"\n",
|
|
|
"# Iterate through channels\n",
|
|
|
"for channel in channels['channels']:\n",
|
|
|
- " print(f'Channel {channel[\"name\"]} Purpose: {channel[\"purpose\"][\"value\"]}\\n')"
|
|
|
+ " print(\n",
|
|
|
+ " f'Channel {channel[\"name\"]} Purpose: {channel[\"purpose\"][\"value\"]}\\n')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -372,7 +369,7 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "slack.channels.history(channel = 'CCCT28F08').body"
|
|
|
+ "slack.channels.history(channel='CCCT28F08').body"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -433,7 +430,8 @@
|
|
|
"\n",
|
|
|
"for user in users['members']:\n",
|
|
|
" # Print some information\n",
|
|
|
- " print(f'\\nUser: {user[\"name\"]}, Real Name: {user[\"real_name\"]}, Time Zone: {user[\"tz_label\"]}.')\n",
|
|
|
+ " print(\n",
|
|
|
+ " f'\\nUser: {user[\"name\"]}, Real Name: {user[\"real_name\"]}, Time Zone: {user[\"tz_label\"]}.')\n",
|
|
|
" print(f'Current Status: {user[\"profile\"][\"status_text\"]}')\n",
|
|
|
" # Get image data and show\n",
|
|
|
" Image(user['profile']['image_192'])"
|
|
@@ -469,12 +467,12 @@
|
|
|
"\n",
|
|
|
"for channel in channels['channels']:\n",
|
|
|
" channel_dict[channel['name']] = channel['id']\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
"user_dict = {}\n",
|
|
|
"\n",
|
|
|
"for user in users['members']:\n",
|
|
|
" user_dict[user['name']] = user['id']\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
"user_dict"
|
|
|
]
|
|
|
},
|
|
@@ -503,15 +501,16 @@
|
|
|
],
|
|
|
"source": [
|
|
|
"# Set the purpose of the channel\n",
|
|
|
- "r = slack.channels.set_purpose(channel_dict['python_content2'], \n",
|
|
|
- " purpose = 'Learning how to use Python for Slack interaction')\n",
|
|
|
+ "r = slack.channels.set_purpose(channel_dict['python_content2'],\n",
|
|
|
+ " purpose='Learning how to use Python for Slack interaction')\n",
|
|
|
"\n",
|
|
|
"channels = slack.channels.list().body\n",
|
|
|
"\n",
|
|
|
"# Iterate through channels\n",
|
|
|
"for channel in channels['channels']:\n",
|
|
|
" if channel['name'] == 'python_content2':\n",
|
|
|
- " print(f'Channel {channel[\"name\"]} Purpose: {channel[\"purpose\"][\"value\"]}\\n')"
|
|
|
+ " print(\n",
|
|
|
+ " f'Channel {channel[\"name\"]} Purpose: {channel[\"purpose\"][\"value\"]}\\n')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -589,10 +588,10 @@
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
"for new_value, name in zip(['Data Scientist and Writer', 'Willk', 'data-sciencing', ':male-technologist:'],\n",
|
|
|
- " ['title', 'display_name', 'status_text', 'status_emoji']):\n",
|
|
|
- " \n",
|
|
|
- " r = slack.users.profile.set(user = user_dict['wjk68'],\n",
|
|
|
- " name = name, value = new_value)\n",
|
|
|
+ " ['title', 'display_name', 'status_text', 'status_emoji']):\n",
|
|
|
+ "\n",
|
|
|
+ " r = slack.users.profile.set(user=user_dict['wjk68'],\n",
|
|
|
+ " name=name, value=new_value)\n",
|
|
|
" if not r:\n",
|
|
|
" print(r.error)"
|
|
|
]
|
|
@@ -679,9 +678,11 @@
|
|
|
"source": [
|
|
|
"import emoji\n",
|
|
|
"\n",
|
|
|
+ "\n",
|
|
|
"def print_emoji(emoji_name):\n",
|
|
|
" print(emoji.emojize(emoji_name, use_aliases=True))\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
+ "\n",
|
|
|
"print_emoji(':runner:')"
|
|
|
]
|
|
|
},
|
|
@@ -729,7 +730,7 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "Image(url = 'https://a.slack-edge.com/c00d19/img/emoji_2017_12_06/sheet_google_64_indexed_256.png')"
|
|
|
+ "Image(url='https://a.slack-edge.com/c00d19/img/emoji_2017_12_06/sheet_google_64_indexed_256.png')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -766,7 +767,7 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "matches = slack.search.messages(query = 'Python').body['messages']['matches']\n",
|
|
|
+ "matches = slack.search.messages(query='Python').body['messages']['matches']\n",
|
|
|
"for match in matches:\n",
|
|
|
" print(f\"Time: {convert_ts(match['ts'])}, Text: {match['text']}\")"
|
|
|
]
|
|
@@ -809,7 +810,7 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "matches = slack.search.files(query = 'plot').body['files']['matches']\n",
|
|
|
+ "matches = slack.search.files(query='plot').body['files']['matches']\n",
|
|
|
"for match in matches:\n",
|
|
|
" print(f\"Time: {convert_ts(match['timestamp'])}, Title: {match['title']}\")"
|
|
|
]
|
|
@@ -873,7 +874,7 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "slack.dnd.set_snooze(num_minutes = 120).body"
|
|
|
+ "slack.dnd.set_snooze(num_minutes=120).body"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1005,10 +1006,10 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "r = slack.chat.post_message(channel = 'python_content', \n",
|
|
|
- " text = 'Have a great day!',\n",
|
|
|
- " username = 'Python Test',\n",
|
|
|
- " icon_url = 'http://devarea.com/wp-content/uploads/2017/11/python-300x300.png')\n",
|
|
|
+ "r = slack.chat.post_message(channel='python_content',\n",
|
|
|
+ " text='Have a great day!',\n",
|
|
|
+ " username='Python Test',\n",
|
|
|
+ " icon_url='http://devarea.com/wp-content/uploads/2017/11/python-300x300.png')\n",
|
|
|
"r.successful"
|
|
|
]
|
|
|
},
|
|
@@ -1043,7 +1044,8 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "slack.channels.history(channel = channel_dict['python_content']).body['messages'][0]['text']"
|
|
|
+ "slack.channels.history(\n",
|
|
|
+ " channel=channel_dict['python_content']).body['messages'][0]['text']"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1072,11 +1074,11 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "r = slack.chat.post_message(channel = 'python_content', \n",
|
|
|
- " text = \"Here's an uplifting story: https://www.forbes.com/sites/stevedenning/2017/11/30/why-the-world-is-getting-better-why-hardly-anyone-knows-it/#181c93b27826\",\n",
|
|
|
- " unfurl_links = True,\n",
|
|
|
- " username = 'Uplift',\n",
|
|
|
- " icon_emoji = ':point_up::skin-tone-5:')\n",
|
|
|
+ "r = slack.chat.post_message(channel='python_content',\n",
|
|
|
+ " text=\"Here's an uplifting story: https://www.forbes.com/sites/stevedenning/2017/11/30/why-the-world-is-getting-better-why-hardly-anyone-knows-it/#181c93b27826\",\n",
|
|
|
+ " unfurl_links=True,\n",
|
|
|
+ " username='Uplift',\n",
|
|
|
+ " icon_emoji=':point_up::skin-tone-5:')\n",
|
|
|
"r.successful"
|
|
|
]
|
|
|
},
|
|
@@ -1113,11 +1115,11 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "r = slack.chat.post_message(channel = 'python_content', \n",
|
|
|
- " text = '<@UCEKVNHPH> Have you read any good books lately?',\n",
|
|
|
- " link_names = True,\n",
|
|
|
- " username = 'Query',\n",
|
|
|
- " icon_emoji = ':green_book:')\n",
|
|
|
+ "r = slack.chat.post_message(channel='python_content',\n",
|
|
|
+ " text='<@UCEKVNHPH> Have you read any good books lately?',\n",
|
|
|
+ " link_names=True,\n",
|
|
|
+ " username='Query',\n",
|
|
|
+ " icon_emoji=':green_book:')\n",
|
|
|
"r.successful"
|
|
|
]
|
|
|
},
|
|
@@ -1152,9 +1154,9 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "r = slack.chat.post_message(channel = 'python_content', \n",
|
|
|
- " text = 'Anyone up for a trip to the store?',\n",
|
|
|
- " as_user = 'willk')\n",
|
|
|
+ "r = slack.chat.post_message(channel='python_content',\n",
|
|
|
+ " text='Anyone up for a trip to the store?',\n",
|
|
|
+ " as_user='willk')\n",
|
|
|
"r.successful"
|
|
|
]
|
|
|
},
|
|
@@ -1182,7 +1184,8 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "slack.channels.history(channel = channel_dict['python_content']).body['messages'][0]['text']"
|
|
|
+ "slack.channels.history(\n",
|
|
|
+ " channel=channel_dict['python_content']).body['messages'][0]['text']"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1209,10 +1212,10 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "r = slack.chat.post_message(channel = 'python_content',\n",
|
|
|
- " text = '<!everyone> *This is not a test!*',\n",
|
|
|
- " username = 'Alert',\n",
|
|
|
- " icon_emoji = ':female-firefighter:')\n",
|
|
|
+ "r = slack.chat.post_message(channel='python_content',\n",
|
|
|
+ " text='<!everyone> *This is not a test!*',\n",
|
|
|
+ " username='Alert',\n",
|
|
|
+ " icon_emoji=':female-firefighter:')\n",
|
|
|
"r.successful"
|
|
|
]
|
|
|
},
|
|
@@ -1238,33 +1241,33 @@
|
|
|
"metadata": {},
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
- "r = slack.chat.post_message(channel = 'random',\n",
|
|
|
- " username = 'Fancy Message',\n",
|
|
|
- " icon_emoji = ':earth_africa:',\n",
|
|
|
- " attachments = [\n",
|
|
|
- " {\n",
|
|
|
- " \"fallback\": \"Required plain-text summary of the attachment.\",\n",
|
|
|
- " \"color\": \"#2eb886\",\n",
|
|
|
- " \"pretext\": \"Optional text that appears above the attachment block\",\n",
|
|
|
- " \"author_name\": \"Fancy Message\",\n",
|
|
|
- " \"title\": \"Slack API Documentation\",\n",
|
|
|
- " \"title_link\": \"https://api.slack.com/\",\n",
|
|
|
- " \"text\": \"Optional text that appears within the attachment\",\n",
|
|
|
- " \"fields\": [\n",
|
|
|
- " {\n",
|
|
|
- " \"title\": \"Priority\",\n",
|
|
|
- " \"value\": \"High\",\n",
|
|
|
- " \"short\": False\n",
|
|
|
- " }\n",
|
|
|
- " ],\n",
|
|
|
- " \"image_url\": \"http://my-website.com/path/to/image.jpg\",\n",
|
|
|
- " \"thumb_url\": \"http://example.com/path/to/thumb.png\",\n",
|
|
|
- " \"footer\": \"Slack API\",\n",
|
|
|
- " \"footer_icon\": \"https://platform.slack-edge.com/img/default_application_icon.png\",\n",
|
|
|
- " \"ts\": 123456789\n",
|
|
|
- " }\n",
|
|
|
- " ]\n",
|
|
|
- " )"
|
|
|
+ "r = slack.chat.post_message(channel='random',\n",
|
|
|
+ " username='Fancy Message',\n",
|
|
|
+ " icon_emoji=':earth_africa:',\n",
|
|
|
+ " attachments=[\n",
|
|
|
+ " {\n",
|
|
|
+ " \"fallback\": \"Required plain-text summary of the attachment.\",\n",
|
|
|
+ " \"color\": \"#2eb886\",\n",
|
|
|
+ " \"pretext\": \"Optional text that appears above the attachment block\",\n",
|
|
|
+ " \"author_name\": \"Fancy Message\",\n",
|
|
|
+ " \"title\": \"Slack API Documentation\",\n",
|
|
|
+ " \"title_link\": \"https://api.slack.com/\",\n",
|
|
|
+ " \"text\": \"Optional text that appears within the attachment\",\n",
|
|
|
+ " \"fields\": [\n",
|
|
|
+ " {\n",
|
|
|
+ " \"title\": \"Priority\",\n",
|
|
|
+ " \"value\": \"High\",\n",
|
|
|
+ " \"short\": False\n",
|
|
|
+ " }\n",
|
|
|
+ " ],\n",
|
|
|
+ " \"image_url\": \"http://my-website.com/path/to/image.jpg\",\n",
|
|
|
+ " \"thumb_url\": \"http://example.com/path/to/thumb.png\",\n",
|
|
|
+ " \"footer\": \"Slack API\",\n",
|
|
|
+ " \"footer_icon\": \"https://platform.slack-edge.com/img/default_application_icon.png\",\n",
|
|
|
+ " \"ts\": 123456789\n",
|
|
|
+ " }\n",
|
|
|
+ " ]\n",
|
|
|
+ " )"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1287,58 +1290,58 @@
|
|
|
"metadata": {},
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
- "r = slack.chat.post_message(channel = 'random', text = 'Play a game!',\n",
|
|
|
- " username = 'Game Overseer', \n",
|
|
|
- " icon_emoji = ':black_joker:',\n",
|
|
|
- " attachments = [\n",
|
|
|
- " {\n",
|
|
|
- " \"text\": \"Choose a game to play\",\n",
|
|
|
- " \"fallback\": \"You are unable to choose a game\",\n",
|
|
|
- " \"callback_id\": \"wopr_game\",\n",
|
|
|
- " \"color\": \"#3AA3E3\",\n",
|
|
|
- " \"attachment_type\": \"default\",\n",
|
|
|
- " \"actions\": [\n",
|
|
|
- " {\n",
|
|
|
- " \"name\": \"game\",\n",
|
|
|
- " \"text\": \"Chess\",\n",
|
|
|
- " \"type\": \"button\",\n",
|
|
|
- " \"value\": \"chess\",\n",
|
|
|
- " \"confirm\": {\n",
|
|
|
- " \"title\": \"Chess is a great game for the mind\",\n",
|
|
|
- " \"text\": \"Are you up to the challenge?\",\n",
|
|
|
- " \"ok_text\": \"Yes\",\n",
|
|
|
- " \"dismiss_text\": \"No\"\n",
|
|
|
- " }\n",
|
|
|
- " },\n",
|
|
|
- " {\n",
|
|
|
- " \"name\": \"game\",\n",
|
|
|
- " \"text\": \"Falken's Maze\",\n",
|
|
|
- " \"type\": \"button\",\n",
|
|
|
- " \"value\": \"maze\",\n",
|
|
|
- " \"confirm\": {\n",
|
|
|
- " \"title\": \"Mazes aren't that interesting!\",\n",
|
|
|
- " \"text\": \"How about the other options?\",\n",
|
|
|
- " \"ok_text\": \"Yes\",\n",
|
|
|
- " \"dismiss_text\": \"No\"\n",
|
|
|
- " }\n",
|
|
|
- " },\n",
|
|
|
- " {\n",
|
|
|
- " \"name\": \"game\",\n",
|
|
|
- " \"text\": \"Thermonuclear War\",\n",
|
|
|
- " \"style\": \"danger\",\n",
|
|
|
- " \"type\": \"button\",\n",
|
|
|
- " \"value\": \"war\",\n",
|
|
|
- " \"confirm\": {\n",
|
|
|
- " \"title\": \"Are you sure?\",\n",
|
|
|
- " \"text\": \"Wouldn't you prefer a good game of chess?\",\n",
|
|
|
- " \"ok_text\": \"Yes\",\n",
|
|
|
- " \"dismiss_text\": \"No\"\n",
|
|
|
- " }\n",
|
|
|
- " }\n",
|
|
|
- " ]\n",
|
|
|
- " }\n",
|
|
|
- " ]\n",
|
|
|
- " )"
|
|
|
+ "r = slack.chat.post_message(channel='random', text='Play a game!',\n",
|
|
|
+ " username='Game Overseer',\n",
|
|
|
+ " icon_emoji=':black_joker:',\n",
|
|
|
+ " attachments=[\n",
|
|
|
+ " {\n",
|
|
|
+ " \"text\": \"Choose a game to play\",\n",
|
|
|
+ " \"fallback\": \"You are unable to choose a game\",\n",
|
|
|
+ " \"callback_id\": \"wopr_game\",\n",
|
|
|
+ " \"color\": \"#3AA3E3\",\n",
|
|
|
+ " \"attachment_type\": \"default\",\n",
|
|
|
+ " \"actions\": [\n",
|
|
|
+ " {\n",
|
|
|
+ " \"name\": \"game\",\n",
|
|
|
+ " \"text\": \"Chess\",\n",
|
|
|
+ " \"type\": \"button\",\n",
|
|
|
+ " \"value\": \"chess\",\n",
|
|
|
+ " \"confirm\": {\n",
|
|
|
+ " \"title\": \"Chess is a great game for the mind\",\n",
|
|
|
+ " \"text\": \"Are you up to the challenge?\",\n",
|
|
|
+ " \"ok_text\": \"Yes\",\n",
|
|
|
+ " \"dismiss_text\": \"No\"\n",
|
|
|
+ " }\n",
|
|
|
+ " },\n",
|
|
|
+ " {\n",
|
|
|
+ " \"name\": \"game\",\n",
|
|
|
+ " \"text\": \"Falken's Maze\",\n",
|
|
|
+ " \"type\": \"button\",\n",
|
|
|
+ " \"value\": \"maze\",\n",
|
|
|
+ " \"confirm\": {\n",
|
|
|
+ " \"title\": \"Mazes aren't that interesting!\",\n",
|
|
|
+ " \"text\": \"How about the other options?\",\n",
|
|
|
+ " \"ok_text\": \"Yes\",\n",
|
|
|
+ " \"dismiss_text\": \"No\"\n",
|
|
|
+ " }\n",
|
|
|
+ " },\n",
|
|
|
+ " {\n",
|
|
|
+ " \"name\": \"game\",\n",
|
|
|
+ " \"text\": \"Thermonuclear War\",\n",
|
|
|
+ " \"style\": \"danger\",\n",
|
|
|
+ " \"type\": \"button\",\n",
|
|
|
+ " \"value\": \"war\",\n",
|
|
|
+ " \"confirm\": {\n",
|
|
|
+ " \"title\": \"Are you sure?\",\n",
|
|
|
+ " \"text\": \"Wouldn't you prefer a good game of chess?\",\n",
|
|
|
+ " \"ok_text\": \"Yes\",\n",
|
|
|
+ " \"dismiss_text\": \"No\"\n",
|
|
|
+ " }\n",
|
|
|
+ " }\n",
|
|
|
+ " ]\n",
|
|
|
+ " }\n",
|
|
|
+ " ]\n",
|
|
|
+ " )"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1374,9 +1377,9 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "r = slack.files.upload(file_ = 'images/volcano_crater.jpg',\n",
|
|
|
- " channels= ['random'], title = 'Volcano Crater',\n",
|
|
|
- " initial_comment = 'This would make a great display background')\n",
|
|
|
+ "r = slack.files.upload(file_='images/volcano_crater.jpg',\n",
|
|
|
+ " channels=['random'], title='Volcano Crater',\n",
|
|
|
+ " initial_comment='This would make a great display background')\n",
|
|
|
"r.successful"
|
|
|
]
|
|
|
},
|
|
@@ -1457,22 +1460,23 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
+ "import seaborn as sns\n",
|
|
|
"import warnings\n",
|
|
|
- "warnings.filterwarnings('ignore', category = FutureWarning)\n",
|
|
|
+ "warnings.filterwarnings('ignore', category=FutureWarning)\n",
|
|
|
"\n",
|
|
|
"# library & dataset\n",
|
|
|
- "import seaborn as sns\n",
|
|
|
"df = sns.load_dataset('iris')\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
"# Basic 2D density plot\n",
|
|
|
"sns.set_style(\"white\")\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
"# Some features are characteristic of 2D: color palette and wether or not color the lowest range\n",
|
|
|
- "sns.kdeplot(df.sepal_width, df.sepal_length, cmap=\"Blues\", shade=True, shade_lowest=True, );\n",
|
|
|
- "plt.title('Good Ole Iris Data Set');\n",
|
|
|
+ "sns.kdeplot(df.sepal_width, df.sepal_length,\n",
|
|
|
+ " cmap=\"Blues\", shade=True, shade_lowest=True, )\n",
|
|
|
+ "plt.title('Good Ole Iris Data Set')\n",
|
|
|
"\n",
|
|
|
"# Save last figure\n",
|
|
|
- "plt.savefig('iris_plot.png', dpi = 500);"
|
|
|
+ "plt.savefig('iris_plot.png', dpi=500)"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1481,10 +1485,10 @@
|
|
|
"metadata": {},
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
- "r = slack.files.upload(file_='iris_plot.png', \n",
|
|
|
- " channels = ['slack_interaction','python_content3'],\n",
|
|
|
- " title = 'Iris Seaborn Plot', \n",
|
|
|
- " initial_comment = \"I've seen this data set way too many times. Seaborn makes some nice plots though.\")"
|
|
|
+ "r = slack.files.upload(file_='iris_plot.png',\n",
|
|
|
+ " channels=['slack_interaction', 'python_content3'],\n",
|
|
|
+ " title='Iris Seaborn Plot',\n",
|
|
|
+ " initial_comment=\"I've seen this data set way too many times. Seaborn makes some nice plots though.\")"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1533,7 +1537,7 @@
|
|
|
"sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0,\n",
|
|
|
" square=True, linewidths=.5, cbar_kws={\"shrink\": .5})\n",
|
|
|
"\n",
|
|
|
- "plt.savefig('heatmap_ex.png');"
|
|
|
+ "plt.savefig('heatmap_ex.png')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1542,10 +1546,10 @@
|
|
|
"metadata": {},
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
- "r = slack.files.upload(file_='heatmap_ex.png', \n",
|
|
|
- " channels = ['slack_interaction','python_content3'],\n",
|
|
|
- " title = 'Correlation Heatmap', \n",
|
|
|
- " initial_comment = \"The correlations are meaningless becuase they are random. Nice plot though.\")"
|
|
|
+ "r = slack.files.upload(file_='heatmap_ex.png',\n",
|
|
|
+ " channels=['slack_interaction', 'python_content3'],\n",
|
|
|
+ " title='Correlation Heatmap',\n",
|
|
|
+ " initial_comment=\"The correlations are meaningless becuase they are random. Nice plot though.\")"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1592,9 +1596,10 @@
|
|
|
"\n",
|
|
|
"if reporting_channel not in channel_list:\n",
|
|
|
" slack.channels.create('training_report')\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
"cid = slack.channels.get_channel_id('training_report')\n",
|
|
|
- "r = slack.channels.set_purpose(cid, 'Report progress while training machine learning models')\n",
|
|
|
+ "r = slack.channels.set_purpose(\n",
|
|
|
+ " cid, 'Report progress while training machine learning models')\n",
|
|
|
"r = slack.channels.set_topic(cid, 'Progress Monitoring')\n",
|
|
|
"r = slack.channels.info(cid).body\n",
|
|
|
"r['channel']['latest']"
|
|
@@ -1673,17 +1678,17 @@
|
|
|
"from keras.callbacks import Callback\n",
|
|
|
"from datetime import datetime\n",
|
|
|
"\n",
|
|
|
+ "\n",
|
|
|
"def report_stats(text, channel):\n",
|
|
|
" \"\"\"Report training stats\"\"\"\n",
|
|
|
- " r = slack.chat.post_message(channel = channel, text = text, \n",
|
|
|
- " username = 'Training Report',\n",
|
|
|
- " icon_emoji = ':clipboard:')\n",
|
|
|
- " \n",
|
|
|
+ " r = slack.chat.post_message(channel=channel, text=text,\n",
|
|
|
+ " username='Training Report',\n",
|
|
|
+ " icon_emoji=':clipboard:')\n",
|
|
|
+ "\n",
|
|
|
" if r.successful:\n",
|
|
|
" return True\n",
|
|
|
" else:\n",
|
|
|
- " return r.error\n",
|
|
|
- " "
|
|
|
+ " return r.error"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1694,23 +1699,24 @@
|
|
|
"source": [
|
|
|
"from timeit import default_timer as timer\n",
|
|
|
"\n",
|
|
|
+ "\n",
|
|
|
"class SlackUpdate(Callback):\n",
|
|
|
" \"\"\"Custom Keras callback that posts to Slack while training a neural network\"\"\"\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" def __init__(self, channel):\n",
|
|
|
" self.channel = channel\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" def on_train_begin(self, logs={}):\n",
|
|
|
- " report_stats(text = f'Training started at {datetime.now()}',\n",
|
|
|
- " channel = reporting_channel)\n",
|
|
|
- " \n",
|
|
|
+ " report_stats(text=f'Training started at {datetime.now()}',\n",
|
|
|
+ " channel=reporting_channel)\n",
|
|
|
+ "\n",
|
|
|
" self.start_time = timer()\n",
|
|
|
" self.train_acc = []\n",
|
|
|
" self.valid_acc = []\n",
|
|
|
" self.train_loss = []\n",
|
|
|
" self.valid_loss = []\n",
|
|
|
" self.n_epochs = 0\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" def on_epoch_end(self, batch, logs={}):\n",
|
|
|
"\n",
|
|
|
" self.train_acc.append(logs.get('acc'))\n",
|
|
@@ -1718,24 +1724,23 @@
|
|
|
" self.train_loss.append(logs.get('loss'))\n",
|
|
|
" self.valid_loss.append(logs.get('val_loss'))\n",
|
|
|
" self.n_epochs += 1\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" message = f'Epoch: {self.n_epochs} Training Loss: {self.train_loss[-1]:.4f} Validation Loss: {self.valid_loss[-1]:.4f}'\n",
|
|
|
- " \n",
|
|
|
- " report_stats(message, channel = self.channel)\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
+ " report_stats(message, channel=self.channel)\n",
|
|
|
+ "\n",
|
|
|
" def on_train_end(self, logs={}):\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" best_epoch = np.argmin(self.valid_loss)\n",
|
|
|
" valid_loss = self.valid_loss[best_epoch]\n",
|
|
|
" train_loss = self.train_loss[best_epoch]\n",
|
|
|
" train_acc = self.train_acc[best_epoch]\n",
|
|
|
" valid_acc = self.valid_acc[best_epoch]\n",
|
|
|
- " \n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" message = f'Trained for {self.n_epochs} epochs. Best epoch was {best_epoch + 1}.'\n",
|
|
|
- " report_stats(message, channel = self.channel)\n",
|
|
|
+ " report_stats(message, channel=self.channel)\n",
|
|
|
" message = f'Best validation loss = {valid_loss:.4f} Training Loss = {train_loss:.2f} Validation accuracy = {100*valid_acc:.2f}%'\n",
|
|
|
- " report_stats(message, channel= self.channel) "
|
|
|
+ " report_stats(message, channel=self.channel)"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1787,13 +1792,13 @@
|
|
|
}
|
|
|
],
|
|
|
"source": [
|
|
|
- "updater = SlackUpdate(channel = reporting_channel)\n",
|
|
|
- "\n",
|
|
|
"import tensorflow as tf\n",
|
|
|
+ "updater = SlackUpdate(channel=reporting_channel)\n",
|
|
|
+ "\n",
|
|
|
"\n",
|
|
|
"# Fit the model for 10 epochs\n",
|
|
|
- "history = model.fit(x_train, y_train, epochs = 12, batch_size = 512,\n",
|
|
|
- " callbacks = [updater], validation_split = 0.4)"
|
|
|
+ "history = model.fit(x_train, y_train, epochs=12, batch_size=512,\n",
|
|
|
+ " callbacks=[updater], validation_split=0.4)"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1846,7 +1851,7 @@
|
|
|
"from utils import plot_history\n",
|
|
|
"\n",
|
|
|
"plot_history(history.history)\n",
|
|
|
- "plt.savefig('training_curves.png');"
|
|
|
+ "plt.savefig('training_curves.png')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1879,8 +1884,8 @@
|
|
|
"\n",
|
|
|
"# Upload file\n",
|
|
|
"comment = f\"Best loss of {min_loss:.4f} at epoch {best_epoch}.\"\n",
|
|
|
- "r = slack.files.upload(file_ = 'training_curves.png', title = \"Training Curves\", channels = [reporting_channel],\n",
|
|
|
- " initial_comment = comment)\n",
|
|
|
+ "r = slack.files.upload(file_='training_curves.png', title=\"Training Curves\", channels=[reporting_channel],\n",
|
|
|
+ " initial_comment=comment)\n",
|
|
|
"r = slack.channels.info(cid).body\n",
|
|
|
"r['channel']['latest']['text']"
|
|
|
]
|
|
@@ -1908,13 +1913,14 @@
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
"from matplotlib import MatplotlibDeprecationWarning\n",
|
|
|
- "warnings.filterwarnings('ignore', category = MatplotlibDeprecationWarning)\n",
|
|
|
+ "warnings.filterwarnings('ignore', category=MatplotlibDeprecationWarning)\n",
|
|
|
+ "\n",
|
|
|
"\n",
|
|
|
- "def plot_image(image, ax = None):\n",
|
|
|
+ "def plot_image(image, ax=None):\n",
|
|
|
" if ax is not None:\n",
|
|
|
- " ax.imshow(image.reshape((28, 28)), cmap = 'Greys')\n",
|
|
|
+ " ax.imshow(image.reshape((28, 28)), cmap='Greys')\n",
|
|
|
" else:\n",
|
|
|
- " plt.imshow(image.reshape((28, 28)), cmap = 'Greys')"
|
|
|
+ " plt.imshow(image.reshape((28, 28)), cmap='Greys')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -1963,29 +1969,30 @@
|
|
|
"metadata": {},
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
- "def plot_predictions(n = 4):\n",
|
|
|
+ "def plot_predictions(n=4):\n",
|
|
|
" \"\"\"Plot test image and predictions\"\"\"\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" # Get random images to plot\n",
|
|
|
" to_plot = np.random.choice(list(range(x_test.shape[0])),\n",
|
|
|
- " size = n, replace = False)\n",
|
|
|
+ " size=n, replace=False)\n",
|
|
|
" correct = []\n",
|
|
|
" # Make predictions and plot each image\n",
|
|
|
" for i in to_plot:\n",
|
|
|
" image = x_test[i]\n",
|
|
|
" probs = model.predict_proba(image.reshape((1, 28, 28, 1)))[0]\n",
|
|
|
" pred = pd.DataFrame({'prob': probs})\n",
|
|
|
- " fig, axs = plt.subplots(1, 2, figsize = (16, 6))\n",
|
|
|
+ " fig, axs = plt.subplots(1, 2, figsize=(16, 6))\n",
|
|
|
" plot_image(image, axs[0])\n",
|
|
|
- " \n",
|
|
|
- " pred['prob'].plot.bar(ax = axs[1])\n",
|
|
|
- " axs[1].set_xlabel('Class'); axs[1].set_ylabel('Probability')\n",
|
|
|
- " axs[1].set_title('Predictions');\n",
|
|
|
+ "\n",
|
|
|
+ " pred['prob'].plot.bar(ax=axs[1])\n",
|
|
|
+ " axs[1].set_xlabel('Class')\n",
|
|
|
+ " axs[1].set_ylabel('Probability')\n",
|
|
|
+ " axs[1].set_title('Predictions')\n",
|
|
|
" plt.savefig(f'images/test-{i}-predictions.png')\n",
|
|
|
" plt.show()\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" correct.append(np.argmax(probs) == np.argmax(y_test[i]))\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" return to_plot, correct"
|
|
|
]
|
|
|
},
|
|
@@ -2045,20 +2052,20 @@
|
|
|
"metadata": {},
|
|
|
"outputs": [],
|
|
|
"source": [
|
|
|
- "def post_predictions(channel, n = 4):\n",
|
|
|
+ "def post_predictions(channel, n=4):\n",
|
|
|
" \"\"\"Post Keras preditions to Slack\"\"\"\n",
|
|
|
- " \n",
|
|
|
+ "\n",
|
|
|
" # Make predictions\n",
|
|
|
- " plot_indexes, correct = plot_predictions(n = n)\n",
|
|
|
- " \n",
|
|
|
- " #Iterate through images and correct indicators\n",
|
|
|
+ " plot_indexes, correct = plot_predictions(n=n)\n",
|
|
|
+ "\n",
|
|
|
+ " # Iterate through images and correct indicators\n",
|
|
|
" for i, r in zip(plot_indexes, correct):\n",
|
|
|
" filename = f'images/test-{i}-predictions.png'\n",
|
|
|
" # Upload the files\n",
|
|
|
- " r = slack.files.upload(file_ = filename, \n",
|
|
|
- " title = \"Predictions\", \n",
|
|
|
- " channels = [channel],\n",
|
|
|
- " initial_comment = 'Correct' if r else 'Incorrect')"
|
|
|
+ " r = slack.files.upload(file_=filename,\n",
|
|
|
+ " title=\"Predictions\",\n",
|
|
|
+ " channels=[channel],\n",
|
|
|
+ " initial_comment='Correct' if r else 'Incorrect')"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -2119,7 +2126,7 @@
|
|
|
"\n",
|
|
|
"\n",
|
|
|
"\n",
|
|
|
- "Looks like this model does pretty well. If you set up a model to train overnight, it would be nice to see these results in the morning! "
|
|
|
+ "Looks like this model does pretty well. If you set up a model to train overnight, it would be nice to see these results in the morning."
|
|
|
]
|
|
|
},
|
|
|
{
|
|
@@ -2158,6 +2165,18 @@
|
|
|
"language": "python",
|
|
|
"name": "python3"
|
|
|
},
|
|
|
+ "language_info": {
|
|
|
+ "codemirror_mode": {
|
|
|
+ "name": "ipython",
|
|
|
+ "version": 3
|
|
|
+ },
|
|
|
+ "file_extension": ".py",
|
|
|
+ "mimetype": "text/x-python",
|
|
|
+ "name": "python",
|
|
|
+ "nbconvert_exporter": "python",
|
|
|
+ "pygments_lexer": "ipython3",
|
|
|
+ "version": "3.6.5"
|
|
|
+ },
|
|
|
"toc": {
|
|
|
"base_numbering": 1,
|
|
|
"nav_menu": {},
|