A guide to creating a chatbot with Rasa stack and Python.
2편에서는 앞서 만든 봇을 슬랙에 배포하는 실습을 진행해본다. 진행에 앞서 1편을 미리 읽어보고 넘어오길 권해드린다.
Rasa Stack 과 파이썬을 활용한 슬랙 챗봇 만들기 (1) A guide to creating a chatbot with Rasa stack and Python
Rasa Installations
1편과는 달리 여기서는 최신 버전의 Rasa Core 를 설치할 것이다. 아나콘다 등을 활용하여 가상환경을 만든 뒤 실습을 진행하길 권해드린다.
우분투 18.04 아나콘다 설치하기 How To Install the Anaconda Python Distribution on Ubuntu 18.04
아나콘다 가상환경을 생성한 후 활성화시킨다.
(base) founder@hilbert:~$ conda create --name rasabot python=3.6 Collecting package metadata: done Solving environment: done ==> WARNING: A newer version of conda exists. <== current version: 4.6.3 latest version: 4.6.4 Please update conda by running $ conda update -n base -c defaults conda ## Package Plan ## environment location: /home/founder/anaconda3/envs/rasabot added / updated specs: - python=3.6 The following packages will be downloaded: package | build ---------------------------|----------------- libedit-3.1.20181209 | hc058e9b_0 188 KB pip-19.0.1 | py36_0 1.8 MB python-3.6.8 | h0371630_0 34.4 MB setuptools-40.8.0 | py36_0 647 KB ------------------------------------------------------------ Total: 37.1 MB The following NEW packages will be INSTALLED: ca-certificates pkgs/main/linux-64::ca-certificates-2019.1.23-0 certifi pkgs/main/linux-64::certifi-2018.11.29-py36_0 libedit pkgs/main/linux-64::libedit-3.1.20181209-hc058e9b_0 libffi pkgs/main/linux-64::libffi-3.2.1-hd88cf55_4 libgcc-ng pkgs/main/linux-64::libgcc-ng-8.2.0-hdf63c60_1 libstdcxx-ng pkgs/main/linux-64::libstdcxx-ng-8.2.0-hdf63c60_1 ncurses pkgs/main/linux-64::ncurses-6.1-he6710b0_1 openssl pkgs/main/linux-64::openssl-1.1.1a-h7b6447c_0 pip pkgs/main/linux-64::pip-19.0.1-py36_0 python pkgs/main/linux-64::python-3.6.8-h0371630_0 readline pkgs/main/linux-64::readline-7.0-h7b6447c_5 setuptools pkgs/main/linux-64::setuptools-40.8.0-py36_0 sqlite pkgs/main/linux-64::sqlite-3.26.0-h7b6447c_0 tk pkgs/main/linux-64::tk-8.6.8-hbc83047_0 wheel pkgs/main/linux-64::wheel-0.32.3-py36_0 xz pkgs/main/linux-64::xz-5.2.4-h14c3975_4 zlib pkgs/main/linux-64::zlib-1.2.11-h7b6447c_3 Proceed ([y]/n)? y Downloading and Extracting Packages libedit-3.1.20181209 | 188 KB | ##################################### | 100% python-3.6.8 | 34.4 MB | ##################################### | 100% setuptools-40.8.0 | 647 KB | ##################################### | 100% pip-19.0.1 | 1.8 MB | ##################################### | 100% Preparing transaction: done Verifying transaction: done Executing transaction: done # # To activate this environment, use # # $ conda activate rasabot # # To deactivate an active environment, use # # $ conda deactivate (base) founder@hilbert:~$
(base) founder@hilbert:~$ source activate rasabot (rasabot) founder@hilbert:~$
(rasabot) founder@hilbert:~$ mkdir rasabot (rasabot) founder@hilbert:~$ cd rasabot (rasabot) founder@hilbert:~/rasabot$
(rasabot) founder@hilbert:~/rasabot$ python -m pip install rasa_nlu[spacy]
(rasabot) founder@hilbert:~/rasabot$ pip show rasa_nlu Name: rasa-nlu Version: 0.14.3 Summary: Rasa NLU a natural language parser for bots Home-page: https://rasa.com Author: Rasa Technologies GmbH Author-email: hi@rasa.com License: Apache 2.0 Location: /home/founder/anaconda3/envs/rasabot/lib/python3.6/site-packages Requires: six, gevent, numpy, matplotlib, coloredlogs, requests, klein, future, typing, ruamel.yaml, cloudpickle, simplejson, jsonschema, tqdm, scikit-learn, boto3, packaging Required-by:
Rasa Core (https://rasa.com/docs/core/installation/)
(rasabot) founder@hilbert:~/rasabot$ python -m pip install -U rasa_core
(rasabot) founder@hilbert:~/rasabot$ pip show rasa_core Name: rasa-core Version: 0.13.2 Summary: Machine learning based dialogue engine for conversational software. Home-page: https://rasa.com Author: Rasa Technologies GmbH Author-email: hi@rasa.com License: Apache 2.0 Location: /home/founder/anaconda3/envs/rasabot/lib/python3.6/site-packages Requires: pydot, slackclient, tensorflow, flask-cors, questionary, python-socketio, keras-preprocessing, rocketchat-API, scipy, jsonpickle, tqdm, python-dateutil, rasa-core-sdk, pykwalify, ruamel.yaml, colorhash, fakeredis, apscheduler, pymongo, flask, typing, redis, numpy, scikit-learn, requests, packaging, webexteamssdk, coloredlogs, networkx, mattermostwrapper, twilio, fbmessenger, pytz, rasa-nlu, jsonschema, pika, terminaltables, keras-applications, gevent, python-telegram-bot, flask-jwt-simple, colorclass Required-by:
(rasabot) founder@hilbert:~/rasabot$ python -m spacy download en_core_web_md Collecting en_core_web_md==2.0.0 from https://github.com/explosion/spacy-models/releases/download/en_core_web_md-2.0.0/en_core_web_md-2.0.0.tar.gz#egg=en_core_web_md==2.0.0 Downloading https://github.com/explosion/spacy-models/releases/download/en_core_web_md-2.0.0/en_core_web_md-2.0.0.tar.gz (120.8MB) 100% |████████████████████████████████| 120.9MB 129.7MB/s Installing collected packages: en-core-web-md Running setup.py install for en-core-web-md ... done Successfully installed en-core-web-md-2.0.0 Linking successful /home/founder/anaconda3/envs/rasabot/lib/python3.6/site-packages/en_core_web_md --> /home/founder/anaconda3/envs/rasabot/lib/python3.6/site-packages/spacy/data/en_core_web_md You can now load the model via spacy.load('en_core_web_md')
(rasabot) founder@hilbert:~/rasabot$ python -m spacy link en_core_web_md en --force; Linking successful /home/founder/anaconda3/envs/rasabot/lib/python3.6/site-packages/en_core_web_md --> /home/founder/anaconda3/envs/rasabot/lib/python3.6/site-packages/spacy/data/en You can now load the model via spacy.load('en')
Ngrok 은 멀티플랫폼 터널링, 리버스 프록시 소프트웨어로 인터넷에서 로컬 구동 네트워크 서비스로의 안전한 터널링을 생성해준다. 간단히 말해서 인터넷에서 로컬 앱에 접근할 수 있도록 해준다는 것이다.
1) ngrok 사이트에서 로그인 후 적절한 파일을 다운로드받는다.2) $ unzip /path/to/ngrok.zip 을 통해 파일압축을 해제한다.
3) $ ./ngrok <authtoken> 형식으로 계정에 접속한다.
4) ngrok 압축을 푼 디렉토리로 이동하여 $ ngrok <authtoken> 이라고 콘솔에 입력한다. 토큰 정보는 여기서 확인할 수 있다.
(rasabot) founder@hilbert:~/src$ ./ngrok authtoken 4xWEiEVWgkoJnSfyLEDgd_2bMEHLSdzQsa2dFU4LzDh Authtoken saved to configuration file: /home/founder/.ngrok2/ngrok.yml
5) 다음과 같이 포트 번호를 지정해 서비스를 시작한다.
(rasabot) founder@hilbert:~/src$ ./ngrok http 5004
Session Status online Account 홍 길 동 (Plan: Free) Version 2.2.8 Region United States (us) Web Interface http://127.0.0.1:4040 Forwarding http://dhidjid78.ngrok.io -> localhost:5004 Forwarding https://dhidjid78.ngrok.io -> localhost:5004
Connections ttl opn rt1 rt5 p50 p90 0 0 0.00 0.00 0.00 0.00
(rasabot) founder@hilbert:~/rasabot$ python nlu_model.py Fitting 2 folds for each of 6 candidates, totalling 12 fits [Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. [Parallel(n_jobs=1)]: Done 12 out of 12 | elapsed: 0.2s finished {'intent': {'name': 'mood_unhappy', 'confidence': 0.5305762770479238}, 'entities': [{'start': 40, 'end': 43, 'value': 'shibes', 'entity': 'group', 'confidence': 0.9894194765511979, 'extractor': 'ner_crf', 'processors': ['ner_synonyms']}], 'intent_ranking': [{'name': 'mood_unhappy', 'confidence': 0.5305762770479238}, {'name': 'goodbye', 'confidence': 0.1254236380112934}, {'name': 'mood_great', 'confidence': 0.10182979881087542}, {'name': 'inform', 'confidence': 0.09953166268980061}, {'name': 'greet', 'confidence': 0.07776521429451069}, {'name': 'mood_affirm', 'confidence': 0.04546210008854246}, {'name': 'mood_deny', 'confidence': 0.01941130905705334}], 'text': 'I am sad, plased send me a picture of a dog'} (rasabot) founder@hilbert:~/rasabot$
(rasabot) founder@hilbert:~/rasabot$ python -m rasa_core_sdk.endpoint --actions actions 2019-02-19 09:00:02 INFO __main__ - Starting action endpoint server... 2019-02-19 09:00:02 INFO rasa_core_sdk.executor - Registered function for 'action_retrieve_image'. 2019-02-19 09:00:02 INFO __main__ - Action endpoint is up and running. on ('0.0.0.0', 5055)\
(rasabot) founder@hilbert:~/rasabot$ python dialogue_management_model.py Processed Story Blocks: 100%|███| 12/12 [00:00<00:00, 3103.25it/s, # trackers=1] Processed Story Blocks: 100%|███| 12/12 [00:00<00:00, 511.91it/s, # trackers=11] Processed Story Blocks: 100%|███| 12/12 [00:00<00:00, 293.16it/s, # trackers=17] Processed Story Blocks: 100%|███| 12/12 [00:00<00:00, 276.09it/s, # trackers=14] Processed actions: 470it [00:00, 12279.86it/s, # examples=382] _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= masking (Masking) (None, 5, 24) 0 _________________________________________________________________ lstm (LSTM) (None, 32) 7296 _________________________________________________________________ dense (Dense) (None, 15) 495 _________________________________________________________________ activation (Activation) (None, 15) 0 ================================================================= Total params: 7,791 Trainable params: 7,791 Non-trainable params: 0 _________________________________________________________________ Epoch 1/100 470/470 [==============================] - 1s 2ms/step - loss: 2.5890 - acc: 0.3043 Epoch 2/100 470/470 [==============================] - 0s 299us/step - loss: 2.3293 - acc: 0.4957 Epoch 3/100 470/470 [==============================] - 0s 302us/step - loss: 2.0503 - acc: 0.4979 Epoch 4/100 470/470 [==============================] - 0s 342us/step - loss: 1.8383 - acc: 0.4979 Epoch 5/100 470/470 [==============================] - 0s 315us/step - loss: 1.7796 - acc: 0.4979 Epoch 6/100 470/470 [==============================] - 0s 311us/step - loss: 1.7170 - acc: 0.4979 Epoch 7/100 470/470 [==============================] - 0s 351us/step - loss: 1.6711 - acc: 0.4979 Epoch 8/100 470/470 [==============================] - 0s 339us/step - loss: 1.6139 - acc: 0.4979 Epoch 9/100 470/470 [==============================] - 0s 351us/step - loss: 1.5845 - acc: 0.4979 Epoch 10/100 470/470 [==============================] - 0s 335us/step - loss: 1.5456 - acc: 0.4979 Epoch 11/100 470/470 [==============================] - 0s 333us/step - loss: 1.4948 - acc: 0.4979 Epoch 12/100 470/470 [==============================] - 0s 281us/step - loss: 1.4581 - acc: 0.4979 Epoch 13/100 470/470 [==============================] - 0s 325us/step - loss: 1.4139 - acc: 0.4979 Epoch 14/100 470/470 [==============================] - 0s 323us/step - loss: 1.3700 - acc: 0.5000 Epoch 15/100 470/470 [==============================] - 0s 376us/step - loss: 1.3357 - acc: 0.5043 Epoch 16/100 470/470 [==============================] - 0s 376us/step - loss: 1.3015 - acc: 0.5191 Epoch 17/100 470/470 [==============================] - 0s 207us/step - loss: 1.2591 - acc: 0.5404 Epoch 18/100 470/470 [==============================] - 0s 224us/step - loss: 1.2281 - acc: 0.5362 Epoch 19/100 470/470 [==============================] - 0s 209us/step - loss: 1.1905 - acc: 0.5617 Epoch 20/100 470/470 [==============================] - 0s 194us/step - loss: 1.1591 - acc: 0.5702 Epoch 21/100 470/470 [==============================] - 0s 186us/step - loss: 1.1229 - acc: 0.5830 Epoch 22/100 470/470 [==============================] - 0s 186us/step - loss: 1.0910 - acc: 0.5872 Epoch 23/100 470/470 [==============================] - 0s 218us/step - loss: 1.0473 - acc: 0.6191 Epoch 24/100 470/470 [==============================] - 0s 200us/step - loss: 1.0314 - acc: 0.6170 Epoch 25/100 470/470 [==============================] - 0s 203us/step - loss: 0.9916 - acc: 0.6426 Epoch 26/100 470/470 [==============================] - 0s 193us/step - loss: 0.9683 - acc: 0.6468 Epoch 27/100 470/470 [==============================] - 0s 196us/step - loss: 0.9296 - acc: 0.6745 Epoch 28/100 470/470 [==============================] - 0s 212us/step - loss: 0.9023 - acc: 0.6872 Epoch 29/100 470/470 [==============================] - 0s 212us/step - loss: 0.8729 - acc: 0.7149 Epoch 30/100 470/470 [==============================] - 0s 196us/step - loss: 0.8722 - acc: 0.6936 Epoch 31/100 470/470 [==============================] - 0s 191us/step - loss: 0.8239 - acc: 0.7340 Epoch 32/100 470/470 [==============================] - 0s 192us/step - loss: 0.8179 - acc: 0.7277 Epoch 33/100 470/470 [==============================] - 0s 195us/step - loss: 0.7904 - acc: 0.7532 Epoch 34/100 470/470 [==============================] - 0s 195us/step - loss: 0.7744 - acc: 0.7809 Epoch 35/100 470/470 [==============================] - 0s 190us/step - loss: 0.7499 - acc: 0.7532 Epoch 36/100 470/470 [==============================] - 0s 206us/step - loss: 0.7061 - acc: 0.7872 Epoch 37/100 470/470 [==============================] - 0s 215us/step - loss: 0.6891 - acc: 0.8085 Epoch 38/100 470/470 [==============================] - 0s 198us/step - loss: 0.7002 - acc: 0.7702 Epoch 39/100 470/470 [==============================] - 0s 208us/step - loss: 0.6630 - acc: 0.8000 Epoch 40/100 470/470 [==============================] - 0s 203us/step - loss: 0.6497 - acc: 0.8064 Epoch 41/100 470/470 [==============================] - 0s 197us/step - loss: 0.6276 - acc: 0.8021 Epoch 42/100 470/470 [==============================] - 0s 195us/step - loss: 0.6059 - acc: 0.8213 Epoch 43/100 470/470 [==============================] - 0s 207us/step - loss: 0.6136 - acc: 0.8106 Epoch 44/100 470/470 [==============================] - 0s 242us/step - loss: 0.5664 - acc: 0.8426 Epoch 45/100 470/470 [==============================] - 0s 196us/step - loss: 0.5551 - acc: 0.8489 Epoch 46/100 470/470 [==============================] - 0s 199us/step - loss: 0.5774 - acc: 0.8255 Epoch 47/100 470/470 [==============================] - 0s 206us/step - loss: 0.5429 - acc: 0.8319 Epoch 48/100 470/470 [==============================] - 0s 216us/step - loss: 0.5256 - acc: 0.8404 Epoch 49/100 470/470 [==============================] - 0s 235us/step - loss: 0.5075 - acc: 0.8574 Epoch 50/100 470/470 [==============================] - 0s 199us/step - loss: 0.5122 - acc: 0.8319 Epoch 51/100 470/470 [==============================] - 0s 196us/step - loss: 0.4940 - acc: 0.8404 Epoch 52/100 470/470 [==============================] - 0s 185us/step - loss: 0.4914 - acc: 0.8426 Epoch 53/100 470/470 [==============================] - 0s 189us/step - loss: 0.4816 - acc: 0.8383 Epoch 54/100 470/470 [==============================] - 0s 187us/step - loss: 0.4551 - acc: 0.8596 Epoch 55/100 470/470 [==============================] - 0s 186us/step - loss: 0.4444 - acc: 0.8617 Epoch 56/100 470/470 [==============================] - 0s 186us/step - loss: 0.4442 - acc: 0.8596 Epoch 57/100 470/470 [==============================] - 0s 192us/step - loss: 0.4378 - acc: 0.8660 Epoch 58/100 470/470 [==============================] - 0s 212us/step - loss: 0.4251 - acc: 0.8660 Epoch 59/100 470/470 [==============================] - 0s 201us/step - loss: 0.4228 - acc: 0.8638 Epoch 60/100 470/470 [==============================] - 0s 221us/step - loss: 0.4125 - acc: 0.8532 Epoch 61/100 470/470 [==============================] - 0s 191us/step - loss: 0.3825 - acc: 0.8596 Epoch 62/100 470/470 [==============================] - 0s 198us/step - loss: 0.3827 - acc: 0.8723 Epoch 63/100 470/470 [==============================] - 0s 203us/step - loss: 0.3824 - acc: 0.8681 Epoch 64/100 470/470 [==============================] - 0s 193us/step - loss: 0.3945 - acc: 0.8553 Epoch 65/100 470/470 [==============================] - 0s 188us/step - loss: 0.3741 - acc: 0.8532 Epoch 66/100 470/470 [==============================] - 0s 182us/step - loss: 0.3532 - acc: 0.8809 Epoch 67/100 470/470 [==============================] - 0s 200us/step - loss: 0.3518 - acc: 0.8787 Epoch 68/100 470/470 [==============================] - 0s 192us/step - loss: 0.3685 - acc: 0.8574 Epoch 69/100 470/470 [==============================] - 0s 201us/step - loss: 0.3623 - acc: 0.8596 Epoch 70/100 470/470 [==============================] - 0s 190us/step - loss: 0.3579 - acc: 0.8532 Epoch 71/100 470/470 [==============================] - 0s 218us/step - loss: 0.3455 - acc: 0.8638 Epoch 72/100 470/470 [==============================] - 0s 202us/step - loss: 0.3267 - acc: 0.8660 Epoch 73/100 470/470 [==============================] - 0s 191us/step - loss: 0.3212 - acc: 0.8872 Epoch 74/100 470/470 [==============================] - 0s 189us/step - loss: 0.3335 - acc: 0.8574 Epoch 75/100 470/470 [==============================] - 0s 196us/step - loss: 0.3117 - acc: 0.8766 Epoch 76/100 470/470 [==============================] - 0s 195us/step - loss: 0.3275 - acc: 0.8702 Epoch 77/100 470/470 [==============================] - 0s 197us/step - loss: 0.3208 - acc: 0.8745 Epoch 78/100 470/470 [==============================] - 0s 190us/step - loss: 0.3161 - acc: 0.8468 Epoch 79/100 470/470 [==============================] - 0s 193us/step - loss: 0.2953 - acc: 0.8787 Epoch 80/100 470/470 [==============================] - 0s 205us/step - loss: 0.3096 - acc: 0.8723 Epoch 81/100 470/470 [==============================] - 0s 188us/step - loss: 0.3079 - acc: 0.8532 Epoch 82/100 470/470 [==============================] - 0s 212us/step - loss: 0.3114 - acc: 0.8638 Epoch 83/100 470/470 [==============================] - 0s 216us/step - loss: 0.2918 - acc: 0.8723 Epoch 84/100 470/470 [==============================] - 0s 197us/step - loss: 0.2886 - acc: 0.8766 Epoch 85/100 470/470 [==============================] - 0s 186us/step - loss: 0.2954 - acc: 0.8745 Epoch 86/100 470/470 [==============================] - 0s 199us/step - loss: 0.2719 - acc: 0.8851 Epoch 87/100 470/470 [==============================] - 0s 197us/step - loss: 0.2785 - acc: 0.8787 Epoch 88/100 470/470 [==============================] - 0s 194us/step - loss: 0.2823 - acc: 0.8638 Epoch 89/100 470/470 [==============================] - 0s 194us/step - loss: 0.2840 - acc: 0.8723 Epoch 90/100 470/470 [==============================] - 0s 219us/step - loss: 0.2669 - acc: 0.8766 Epoch 91/100 470/470 [==============================] - 0s 191us/step - loss: 0.2617 - acc: 0.8894 Epoch 92/100 470/470 [==============================] - 0s 216us/step - loss: 0.2646 - acc: 0.8830 Epoch 93/100 470/470 [==============================] - 0s 191us/step - loss: 0.2688 - acc: 0.8830 Epoch 94/100 470/470 [==============================] - 0s 211us/step - loss: 0.2820 - acc: 0.8723 Epoch 95/100 470/470 [==============================] - 0s 204us/step - loss: 0.2520 - acc: 0.8915 Epoch 96/100 470/470 [==============================] - 0s 194us/step - loss: 0.2597 - acc: 0.8617 Epoch 97/100 470/470 [==============================] - 0s 199us/step - loss: 0.2509 - acc: 0.8830 Epoch 98/100 470/470 [==============================] - 0s 197us/step - loss: 0.2517 - acc: 0.8809 Epoch 99/100 470/470 [==============================] - 0s 193us/step - loss: 0.2446 - acc: 0.8809 Epoch 100/100 470/470 [==============================] - 0s 188us/step - loss: 0.2529 - acc: 0.8915
run_app.py 파일을 실행시켜 에이전트를 구동한다. 단, 실행 전에 해당 스크립트에 슬랙 토큰 정보가 정확히 들어가 있는지 확인한다.
OAuth & Permissons 의 2개의 토큰 정보 중 하단에 있는 Bot User OAuth Access Token 정보를 하단 스크립트 input_channel 정보에 입력한다.
input_channel = SlackInput('#your bot user authentication token')
run_app.py
from rasa_core.channels.slack import SlackInput from rasa_core.agent import Agent from rasa_core.interpreter import RasaNLUInterpreter import yaml from rasa_core.utils import EndpointConfig nlu_interpreter = RasaNLUInterpreter('./models/nlu/default/current') action_endpoint = EndpointConfig(url="http://localhost:5055/webhook") agent = Agent.load('./models/dialogue', interpreter = nlu_interpreter, action_endpoint = action_endpoint) input_channel = SlackInput('xoxb-514185865477-514638817877-ZlAUhYSuoydYHkl0oCrUU7MC' #your bot user authentication token ) agent.handle_channels([input_channel], 5004, serve_forever=True)
https://<your_ngrok_url>/webhooks/slack/webhook
마지막으로, 다음 2개의 Workplace events 를 받기로 한다.
- app_mention : 누군가가 자기 이름을 호출했을 경우 봇이 반응하도록 한다
- message_im : 봇에게 DM (direct messages)을 보낼 수 있게 한다.
그리고 다음과 같이 run_app.py 파일을 실행한다.
(rasabot) founder@hilbert:~/rasabot$ python run_app.py
Let’s Talk
1) custom actions 서버가 구동중인지 확인한다
2) ngrok 가 5004번 포트에서 구동중인지 확인한다
3) Slack 인터페이스에서 봇과 대화한다
엄청나게 힘든 작업처럼 들릴지 몰라도 한 단계씩 따라하다보면 어느 순간 Zoe 라는 멋진 챗봇을 완성할 수 있을 것이다.
아래와 같이 3개의 터미널이 돌아가고 있다.
[원문] https://towardsdatascience.com/building-a-conversational-chatbot-for-slack-using-rasa-and-python-part-2-ce7233f2e9e7
'프로그래밍 Programming' 카테고리의 다른 글
서프라이즈 라이브러리를 활용한 추천시스템 구축 및 검증 Building and Testing Recommender Systems With Surprise, Step-By-Step (0) | 2019.03.02 |
---|---|
주피터랩 살펴보기 Jupyter Lab: Evolution of the Jupyter Notebook (0) | 2019.02.25 |
Rasa Stack 과 파이썬을 활용한 슬랙 챗봇 만들기 (1) A guide to creating a chatbot with Rasa stack and Python (0) | 2019.02.22 |
핀터레스트 위젯 빌더 Pintereest Widget builder (0) | 2019.02.16 |
웹사이트, 블로그에 핀터레스트 핀 넣기 (0) | 2019.02.16 |
댓글을 사용할 수 없습니다.