LM Studio + LangChain + ChainlitでローカルPCに生成AIのチャットアプリを作ってみた

以前の記事ではLM StudioでローカルPCに立てたLLMに、REST APIでアクセスしてみました。
今回はその仕組を使ってLangChainと連携し、さらにChainlitでお手軽にチャットアプリを作ってみました。

事前準備

Windows PCであればAnaconda Promptを起動し、仮想環境をアクティベートします。

> activate <仮想環境名>

LangChainとChainlitをインストールします。

> pip install langchain
> pip install chainlit

LM StudioのLLMとLangChain経由で連携し、Chainlitでアプリを起動するコードの作成

Chainlitの公式サイトにあるLangChainと連携するチュートリアルを参照し、今回のコードは以下のように実装しました。
LM Studio上のLLM (今回はVicuna) と連携するため、ChatOpenAIメソッドの引数 base_url には、LM Studioで立てたローカルLLMサーバのエンドポイントを指定しています。

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser
from langchain.schema.runnable import Runnable
from langchain.schema.runnable.config import RunnableConfig

import chainlit as cl

@cl.on_chat_start
async def on_chat_start():
    model = ChatOpenAI(base_url="http://localhost:1234/v1", api_key="not-needed", streaming=True)
    prompt = ChatPromptTemplate.from_messages(
        [
            (
                "system",
                "質問に対して100字で回答してください。",
            ),
            ("human", "{question}"),
        ]
    )
    runnable = prompt | model | StrOutputParser()
    cl.user_session.set("runnable", runnable)

@cl.on_message
async def on_message(message: cl.Message):
    runnable = cl.user_session.get("runnable")  # type: Runnable

    msg = cl.Message(content="")

    async for chunk in runnable.astream(
        {"question": message.content},
        config=RunnableConfig(callbacks=[cl.LangchainCallbackHandler()]),
    ):
        await msg.stream_token(chunk)

    await msg.send()

上記コードを chat_test.py として保存します。

実行してみる

作成したPythonのコードを実行してみます。
Chainlitを起動する際は、以下のように実行します。

> chainlit run chat_test.py -w

するとChainlitのサーバが起動し、以下のようにチャットアプリが使えるようになります。

01

試しに質問してみると、次の通りローカルのLLMと連携して回答してくれました。

02

以上のように、LM Studio + LangChain + Chainlitを使えば、生成AIを使ったチャットアプリがローカル環境で手軽に出来ちゃいました。
生成AIを使ったアプリ開発の環境として使えるかもしれませんね。

pgvectorを使ってPostgreSQL内の既存のリレーショナル表にベクトルデータを格納してみた

PostgreSQLにはベクトルデータを扱えるようにするために、pgvectorという拡張機能があります。
これによって、既存のリレーショナル形式のデータとベクトルデータを同じ表内で利用できます。
ベクトルデータのみ専用のDBを設けて、そちらに格納する方法も考えられますが、
開発効率やDB運用の手間を考えると、同じDB上に集約して使えるほうが良さそうです。
ということで、今回はPostgreSQLを使い、既存のリレーショナル表に対して
pgvectorを使ってベクトルデータを格納する方法を検証してみました。

事前準備

PostgreSQL、およびPython環境の事前準備については以下の記事を参考にしてください。
生成AI (Cohere)+LangChain+Vector Database (PostgreSQL)でRAGを試してみた
上記の「必要なPythonパッケージのインストール」から「PostgreSQLへのホスト名指定でのログインを有効化」までが対象作業です。

環境が整ったら、検証に使う表を作成します。

CREATE TABLE products_v (
    product_id SERIAL PRIMARY KEY,
    product_name VARCHAR(255),
    manufacturer_name VARCHAR(255),
    product_overview TEXT,
    price FLOAT,
    release_date DATE,
    embedding vector(4096)
);

サンプルデータを入れます。

INSERT INTO products_v (product_name, manufacturer_name, product_overview, price, release_date)
    VALUES ('Tiny Tunes Piano', 
        'Playful Minds Co.', 
        'A colorful and musical toy piano that lets toddlers play and learn songs. The piano has 12 keys, each with a different animal sound and a corresponding sticker. The piano also has a mode switch that allows toddlers to choose between animal sounds, musical notes, or songs. The piano comes with a songbook that teaches toddlers how to play 10 popular nursery rhymes.', 
       29.99, 
       '2023-12-01');

INSERT INTO products_v (product_name, manufacturer_name, product_overview, price, release_date)
    VALUES ('Tiny Blocks Castle', 
        'Playful Minds Co.', 
        'A set of 50 wooden blocks in various shapes and colors that toddlers can use to build their own castle. The blocks are easy to stack and connect with magnets. The set also includes a drawbridge, a flag, and two knight figures. The blocks are made of natural and eco-friendly materials and are safe for toddlers to play with.', 
       39.99, 
       '2024-01-15');

INSERT INTO products_v (product_name, manufacturer_name, product_overview, price, release_date)
    VALUES ('Tiny Pals Farm', 
        'Playful Minds Co.', 
        'A fun and interactive toy farm that introduces toddlers to farm animals and their sounds. The farm has a barn, a silo, a tractor, and a fence. The farm also has 10 animal figures, each with a button that plays its sound when pressed. The farm has a sensor that recognizes the animal figures and plays a song or a fact about them when placed on the farm.', 
       49.99, 
       '2024-02-01');

Pythonスクリプトの作成

既存の products_v 表の product_overview 列の値を使い、Cohereのモデルを使ってベクトルデータを生成します。
出来たベクトルデータをUPDATE文で products_v 表の embedding 列に格納します。
ちなみに embedding 列にベクトルデータを格納する際は、CohereのAPIから返ってきた配列のベクトルデータを、NumPy配列に変換して格納する必要があります。

import os
import numpy as np
import psycopg2
from pgvector.psycopg2 import register_vector
from langchain.vectorstores.pgvector import PGVector
from langchain.embeddings import CohereEmbeddings

COHERE_API_KEY = os.environ['COHERE_API_KEY']
embeddings = CohereEmbeddings(cohere_api_key=COHERE_API_KEY)

# データベースへの接続情報を設定します
conn = psycopg2.connect(
    host="localhost",
    database="postgres",
    user="postgres",
    password="postgres"
)

register_vector(conn)

# カーソルを作成します
cur = conn.cursor()

# SQLクエリを実行します
cur.execute("SELECT product_id, product_overview FROM products_v;")

# 結果を取得します
rows = cur.fetchall()

# 各行のproduct_overviewをベクトル化してproducts_vに格納します
for row in rows:
    doc_result = embeddings.embed_documents([row[1]])
    cur.execute('UPDATE products_v SET embedding = %s WHERE product_id = %s;', (np.array(doc_result[0]), row[0]))

# カーソルと接続を閉じます
conn.commit()
cur.close()
conn.close()

上記コードを embedding.py として保存します。

実行結果

コードを実行します。

$ python embedding.py

psqlで products_v 表の embedding 列を確認します。

SELECT product_id, embedding FROM products_v;

 product_id | embedding                                                                              
------------+----------------------------------------------------------------------------------------
          1 | [-0.31567383,-2.484375,0.58935547,2.5546875,-1.5625,0.2590332,2.1933594,1.703125,0.8295 ...
          2 | [1.0498047,-0.9082031,-1.8886719,0.9897461,-2.6992188,-1.2197266,1.921875,1.0507812,-0. ...
          3 | [1.6728516,-0.46484375,-0.9838867,2.4414062,0.55029297,-0.9790039,0.78808594,1.7128906, ...

以上のようにすれば、リレーショナルデータとベクトルデータを同じ表で扱えます。
データモデルに応じて種類の異なるDBを構築・運用する必要がなくなり、開発効率や運用効率の向上に繋がるのではないでしょうか。

LM Studioを使ってローカルPCで稼働させたLLMにOpenAI互換のREST APIで問い合わせてみた

LM Studioというデスクトップ・アプリを使うと、手元のPCで色々なLLMを試せます。
GPUがない、もしくはオンチップのGPUしかない環境でもLLMを動かせるのが特徴です(ただしCPUとメモリはかなり消費します)。
今回はLM Studioを使ってインストールした Vicuna というLLMに対して、REST API経由でチャット機能を試してみました。
ちなみに Vicuna は日本語に対応したオープンソースのLLMで、Llama2ベースのモデルとなっています。
使ってみた感じ、性能は割りと良さげです。
ちなみにREST APIはOpneAI互換となっているため、OpenAI向けのREST APIで使えます。

LM StudioにVicunaをインストール

LM Studioの検索フォームで「vicuna-13b」と検索し、モデルをダウンロードします。
私は「vicuna-13b-v1.5-16k.Q5_K_M.gguf」をダウンロードしました。

01

Vicunaをサーバとして起動

次にサイドメニューの「Local Server」へアクセスし、上部のプルダウンメニューから先程ダウンロードしたLLMを選択します。
選択できたら緑の「Start Server」を押下します。

02

サーバが起動すると「Server logs」に以下のような出力がみられます。

03

ちなみにサーバを起動すると大量にメモリを消費します。
私のPCでは以下のように負荷が掛かり、LM Studioによって約10GBのRAMを消費しています。

04

Python環境の準備

今回はLLMにアクセスする処理をPythonで書きます。
そのためPythonの環境を準備します。
各種パッケージの導入にはAnacondaを使いました。

Anacondaをインストールしたら「Anaconda Prompt」を起動します。

05

本検証で使うPythonの仮想環境を作成します。

> conda create -n gai

作成できたら仮想環境を切り替えます。

> conda activate gai

OpenAIのREST APIを実行するのに必要なパッケージをインストールします。
APIの仕様の対応状況から、openaiのバージョンは0.28未満を指定しています。

> conda install "openai<0.28"

コードの実行

Vicunaのチャット機能を使うコードを実行します。
サンプルコードは以下の通り用意しました。
質問として「Oracle Databaseについて200文字で簡潔に説明してください。」という文章を投げています。

import openai

openai.api_base = "http://localhost:1234/v1" # LLMのローカルサーバへの接続情報
openai.api_key = "" # APIキーは空欄でOK

completion = openai.ChatCompletion.create(
  model="local-model",
  messages=[
    {"role": "user", "content": "Oracle Databaseについて200文字で簡潔に説明してください。"}
  ]
)

print(completion.choices[0].message.content)

以下が実行結果です。

> python chat_test.py
 Oracle Databaseは、世界最大級のリレーショナルデータベース管理システムです。データの永続性や一貫性を保ちながら、高速かつ安全にデータを処理します。クラスタリング技術により、データのバックアップと回復も容易に行えます。企業や組織のデータ管理に広く使用されています。

それっぽい回答を得られました。
ちなみに回答生成中のCPU負荷は以下のようになっていました。
8コア12スレッドありますが、全て100%に張り付いています。
ちなみに私の環境はオンチップのGPUしかありませんが、それも使わない設定にしています。

06

またサーバログには以下のように出力されていました。
APIのリクエスト情報や処理経過、最終結果の情報が表示されています。

07

以上がLM Studioを使ったローカルPCでのLLMサーバの実行と、REST APIによるアクセスの基本例でした。
次はローカルにベクトル・データベースを立てて、RAGも試してみたいと思います。

OCI Always Freeのリソースを使って自作Webアプリを公開してみた

OCI Always Freeのリソースだけを使って自作Webアプリを公開してみました。
http://132.145.161.254/drawlogic/
こちらは「ロジックツリー生成ツール」です。
ロジックツリーを使って考え事する際に、
ツリーを簡単に作れるツールが欲しかったので作ってみました。

ソースコードは以下で公開しています。
https://github.com/mago1chi/drawtree
Webアプリのフレームワークは「Django」を、
ツリー描画は「Graphviz」を使っています。

またAlways Freeについては以下をご覧ください。
Always Freeリソースの詳細
使ったリソースはCompute、NetworkingとBlock Volumeです。
DNSサービスも含まれてたら良かったのですが、
Always Free対象外ということでIPでの公開です。

クラウドを使ったインフラ構築、アプリ開発の良い勉強になりました。

Django+Apache2+mod_wsgiでWebアプリを公開するまでの手順メモ

Django+Apache2+mod_wsgiでWebアプリを公開するまでの手順です。
色々と大変でした…

なお以降の手順はOracle Cloud InfrastructureのCompute上に構築した
「Oracle Linux 7.7」で試しています。
またDjangoアプリ自体は作成済みであることを前提としています。

手順

パッケージインストール

root$ yum update
root$ yum install -y python3 python3-pip python3-setuptools python3-wheel python3-venv python3-dev python3-devel apache2 apache2-dev httpd httpd-devel git apxs2 apxs gcc cc

Apacheの起動設定

systemctl enable  httpd.service
systemctl start  httpd.service

FW設定

firewall-offline-cmd --add-service=http
systemctl restart firewalld

SELinux無効化

root$ getenforce
root$ cp -piv /etc/selinux/config /etc/selinux/config.`date "+%Y%m%d"`
root$ vim /etc/selinux/config
## SELINUX=disabled に修正
root$ shutdown -r now

プロジェクト配置
※プロジェクトがgithubにある場合

root$ cd /var/www/html
root$ git clone https://github.com/xxxxx/yyyyy

python仮想環境の作成

root$ cd /var/www/html/xxxxx
root$ python3 -m venv env
root$ source env/bin/activate

依存モジュールのインストール
※以降の手順はpython仮想環境上で実行

## requirements.txtファイルはプロジェクトに合わせて作成(pip freezeで生成)
## ただしDjangoはsqlite3エラー対応のため「2.1.0」を指定
## 
## Django==2.1.0

root$ pip install wheel
root$ pip install -r /tmp/requirements.txt

sqlite3の最新化
※後述エラーのため実行したが、Django 2.1.0なら不要かも?

root$ cd /root
root$ wget https://www.sqlite.org/2019/sqlite-autoconf-3290000.tar.gz
root$ tar zxvf ./sqlite-autoconf-3290000.tar.gz
root$ cd ./sqlite-autoconf-3290000
root$ ./configure --prefix=/usr/local
root$ make
root$ make install
root$ mv /bin/sqlite3 /bin/sqlite3_old
root$ ln -s /usr/local/bin/sqlite3 /bin/sqlite3
root$ echo 'export LD_LIBRARY_PATH="/usr/local/lib"' >> ~/.bashrc
root$ source ~/.bashrc

Django管理コマンド実行

root$ python manage.py migrate         #DB定義更新
root$ python manage.py createsuperuser #管理ユーザー作成

ディレクトリ・ファイル権限変更

root$ chmod 755 /var/www/html
root$ chmod 777 /var/www/html/xxxxx
root$ chmod 777 /var/www/html/xxxxx/db.sqlite3

Apache設定
※以下は自分のプロジェクト構成に応じて修正

root$ vim /etc/httpd/conf/httpd.conf

## 以下を追記
LoadModule wsgi_module modules/mod_wsgi.so
WSGIScriptAlias / /var/www/html/xxxxx/zzzzz/wsgi.py
WSGIPythonHome /var/www/html/xxxxx/env
WSGIPythonPath /var/www/html/xxxxx



    Require all granted



Alias /static/ /var/www/html/xxxxx/static

  Require all granted

ブラウザでサイトにアクセスして動作確認!
序に以下コマンドでエラーが出ないかもチェック

tail -f /var/log/httpd/error_log

つまづいた所

  • サイトにアクセスすると「django.core.exceptions.ImproperlyConfigured: SQLite 3.8.3 or later is required (found 3.7.17).」エラーが発生して正しく表示されない
    • Djangoのバージョンを「2.1.0」にすることで回避
  • 「attempt to write a readonly database」が発生してセッション情報を扱う処理でエラーが起きる
    • SELinuxを無効化して対応
  • スタティックファイルの公開がうまく行かない
    • こちらは現在対応中です…

参考資料

PythonのGraphviz導入から日本語表記まで

Graphvizの導入

Anacondaでは以下ライブラリをインストールします。

  • graphviz
  • python-graphviz
  • pydotplus

コマンドはこちら。

conda install graphviz
conda install python-graphviz
conda install pydotplus

さらに環境変数のパスを通します。
これをしないとrenderしたときに以下エラーが出ます。

graphviz.backend.ExecutableNotFound: failed to execute ['dot', '-Tpng', '-O', 
'graphs'], make sure the Graphviz executables are on your systems' PATH

日本語表記対応

Graphvizをデフォルトで使用すると下記画像のように文字化けします。

garbled

正しく表示するにはコード中でnodeのfontnameを設定します。

from graphviz import Digraph

graph_body = Digraph(format="png")
graph_body.attr('node', shape='box', fontname='MS Gothic') # ←★ここのfontnameで日本語対応フォントを設定★

これで正しく日本語が表示されます。

correct

「第4回 ドワンゴからの挑戦状 予選」を解いてみた

「第4回 ドワンゴからの挑戦状 予選」の問題が公開されているので
A問題とB問題にチャレンジしてみました。

第4回 ドワンゴからの挑戦状 予選

言語はpythonを選びました。
ちなみに私は競技プログラミングに関してはド素人です。
TopCoderもちょっとだけやってましたが、
がんばってgreen coderになれるかどうかってレベルです。

ニコニコ文字列判定

4文字の文字列が “xyxy” の並びになっているか判定する問題です。

s = input()

if s[0] == s[2] and s[1] == s[3]:
    print(&quot;Yes&quot;)
else:
    print(&quot;No&quot;)

最初出力を “yes” と “no” にしており、
大文字にすべき箇所を小文字にしていたので全然通りませんでした。
問題はちゃんと読まなきゃダメですね。。。

2525文字列分解

文字列 s を 25 が並ぶ文字列に分解し、
いくつの部分文字列に分解できるか出力します。
私のコードは 25 という文字列を長さ 0 になるまで除去し続け、
そのループ回数を結果として出力する、という処理になっています。

s = input()

if len(s) % 2:
    print(-1)
    exit()

if s[0] == &quot;5&quot;:
    print(-1)
    exit()

if len(list(filter(lambda x: x is &quot;2&quot;, s))) != len(list(filter(lambda x: x is &quot;5&quot;, s))):
    print(-1)
    exit()

split_count = 0
while True:
    s = s.replace(&quot;25&quot;, &quot;&quot;)

    if len(s) == 0:
        split_count += 1
        break

    elif s[0] == &quot;5&quot;:
        print(-1)
        exit()

    else:
        split_count += 1

print(split_count)

こちらは一発で通りましたが、私の解法は計算効率が悪いです。
より効率の良いコードは結果ページから参照できます。

余力があればD問題まではチャレンジしてみたいと思います。

SlackBotとShangriLa Anime APIの連携

はじめに

前回はSlackBotのサンプルを作ってみましたが、
応答がワンパターンで面白みのないBotとなっていました。
今回は以下で仕様が公開されているShangriLa Anime APIと連携させ、
アニメに関する情報をやり取りできるBotを作ってみました。

ShangriLa Anime API
https://github.com/Project-ShangriLa/sora-playframework-scala

具体的には、「anime: 2016,2」などとチャットへ書き込むと、
ShangriLa Anime APIへ問い合わせることで、
2016年の2クール目に放映されていたアニメのタイトル一覧が
Slackに表示されるようにしました。

実装概要

未だBot初学者ということもあり、
以下のようになるべくシンプルな実装にしました。

  • チャットに書き込まれたテキストを取得

  • テキスト冒頭に”anime:”という文字列がある場合は
    Botが反応する

  • “anime:”のあとに4桁の整数と2桁の整数がある場合は
    それらをパースし、APIへ問い合わせる「年」と「クール」として扱う

  • パースして得られた二つの整数をもとにAPIへ問合せ、
    戻ってきたJSONデータからアニメのタイトル一覧を抽出

  • 抽出したタイトルをSlackへ投稿するのに適した形にまとめ、
    Slackへ投稿する

コード

概要で述べた処理を以下のようにPythonで実装しました。

import time
import sys
import os
import re
import json
import urllib.request

from slackclient import SlackClient

## basic information to call slack api
token = "your token"
channel = "your channel ID"
user_name = "your bot user name"
icon_url = "your bot's icon image url"

api_interface = SlackClient(token)

if api_interface.rtm_connect():
    while True:
        data = api_interface.rtm_read()

        if len(data) >= 1 and "text" in data[0]:
            matched_obj = re.match("^anime:\s*([0-9]{4})\s*,\s*([0-9])$", data[0]["text"])

            if matched_obj is not None:
                year = matched_obj.group(1)
                term = matched_obj.group(2)

                with urllib.request.urlopen('http://api.moemoe.tokyo/anime/v1/master/'+year+'/'+term) as response:
                    contents = json.loads(response.read().decode('utf8'))

                    message = ""
                    for each_content in contents:
                        message += each_content['title'] + "\n"

                    print(api_interface.api_call("chat.postMessage", username=user_name, channel=channel, \
                        text=message, icon_url=icon_url))

        time.sleep(1)

23行目が受けとったテキストのパース処理になります。
見ての通り、正規表現で処理しています。

取得した「年」と「クール」の情報をもとに29行目でAPIへ問合せ、
30行目でJSONデータを”contents”に格納しています。

33、34行目でSlackへ投稿するテキストとして整形し、
36、37行目でSlackへ投稿しています。

これを実際に動かすと以下のように応答してくれます。

01_bottest

おわりに

前回があまりにも簡単すぎたので、
少しだけ工夫を凝らしてみました。
次回Botで遊ぶ際はもっと面白くて役に立つものに
挑戦してみたいと思います。

PythonでSlackBotを作ってみました

はじめに

巷ではBotとAIを組み合わせて色々やりましょう、
という取組みが散見される今日この頃。
Slackの他LINEでもBot用のAPIが公開されていたりします。

「私もBotで色々遊んでみたい」という訳で、
今回はSlackBotを使って物凄くシンプルなBotを作ってみました。
以降ではBot作成のための下準備から実装までをご説明していきます。
ちなみに実装はPythonを利用しました。

下準備|Botユーザ作成

まずは以下の開発者向けページにアクセスし、
“Bot Users”というリンクを押下します。
開発者向けページ

doctop

“Custom bot users”という項目の
“creating a new bot user”リンクにアクセスします。

create_botuser

botユーザのユーザ名を入力します。

input_bot_name

遷移先のページでAPI Tokenを確認し、
どこかにメモしておきます。

get_token

同ページでアイコンとして使う画像をアップロードします。

ul_icon

アップロード後に右クリックメニュー等を利用して
画像のURLをクリップボードにコピーし、
どこかにメモしておきます。

image_url

下準備|チャネル作成

次にチャット画面のサイドメニューにある
“CHANNELS”の横のボタンを押下します。

add_channel

必要事項を入力してチャネルを作成した後、
そのチャネルに切り替えます。
※入力内容は特に気にしなくて大丈夫です。

すると以下のようなURLにアクセスしますので、
URL中にあるチャネルのIDをどこかにメモしておきます。
※{channel ID}の箇所です。
https://{team name}.slack.com/messages/{channel ID}/

実装

以上で必要な設定が完了し、
実装時に入力する情報も入手しました。
あとは実装するのみです。

冒頭でも述べた通り、
今回はPythonで実装しました。
理由としては次の3つが挙げられます。

  • 使い慣れている言語だから
  • 機械学習のライブラリと連携する場合に有利そうだから
  • JavaScriptの実装は情報が多いので、差別化を図るため

モノリシックな作りで工夫もありませんが、
サンプルコードとしての実装は以下の通りです。

import time
import sys
import os

from slackclient import SlackClient

## basic information to call slack api
token = "your token"
channel = "your channel id"
user_name = "your bot user name"
message = "てすてす"
icon_url = "image url of your bot user"

api_interface = SlackClient(token)

if api_interface.rtm_connect():
    while True:
        data = api_interface.rtm_read()

        if len(data) >= 1 and "text" in data[0]:
            if "bot:" in data[0]["text"]:
                print(api_interface.api_call("chat.postMessage", username=user_name, channel=channel, \
                        text=message, icon_url=icon_url))

        time.sleep(1)

コード中で利用している”SlackClient”というパッケージは
pip等を使って導入しておく必要があるかもしれません。

また8~12行目の各種情報は、
下準備でメモしておいた各情報を入力します。

動作確認

上記のコードを例えば
“sample.py”というファイルに保存し、
以下のように実行しておきます。

python sample.py

その後、下準備で作成した
Slackのチャットルームにアクセスし、
「bot:」と入力してメッセージを送信すると
ひたすら「てすてす」と返信してくれます。

operation_check

おわりに

今回はSlackBotのお勉強も兼ねて
非常に簡単なBotを作成してみました。
次回は他のサービスと連携するなどし、
何かしらに役立つBotの作成に挑戦してみたいと思います。

EC2+DockerでJupyter Notebookを動かす part2

前回はEC2インスタンスを作成し、Dockerをインストールしました。
今回はJupyter NotebookをDocker上で動かし、
EC2インスタンスのネットワーク設定をいじることで
外部からJupyter Notebookへアクセスできるようにします。

Jupyter NotebookのDockerイメージ取得・起動

まずはJupyter NotebookのDockerイメージを取得します。

docker pull jupyter/datascience-notebook

Jupyter Notebookのイメージ取得ができたことを確認します。

docker images jupyter/datascience-notebook

REPOSITORY                     TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
jupyter/datascience-notebook   latest              91f5bc10a994        36 hours ago        6.828 GB

イメージの取得ができたら、あとはDockerイメージを起動します。

docker run -it --name notebook -p 80:8888 jupyter/datascience-notebook

上記コマンドを実行するとJupyter Notebookにアクセスするための
トークンが標準出力されますので、それを使ってアクセスします。
その後は”Ctrl-p -> Ctrl-q”でイメージ内からログアウトし、
ターミナル等を閉じても稼働し続けるようにします。

EC2インスタンスのNW設定

次にEC2インスタンスのネットワーク設定を下記の手順で行います。

  1. サイドメニューの「セキュリティグループ」を押下
  2. Jupyter Notebookが稼働しているEC2インスタンスの
    セキュリティグループを選択
  3. 下ウィンドウの「インバウンド」タブを選択
  4. 編集ボタンを押下
  5. 「インバウンドルールの編集」画面で「ルールの追加」を押下
  6. 以下の入力内容でルールを追加
    • タイプ|HTTP
    • プロトコル|TCP
    • ポート範囲|80
    • 送信元|カスタム、0.0.0.0/0
  7. 「保存」ボタンを押下

security group

add rule

以上の設定をすると、EC2インスタンスのグローバルIPを指定すれば
任意のIPからJupyter Notebookにアクセスできます。

Jupyter Notebook Toppage

これで家からはもちろん、出先や会社からでも
手軽にデータ分析ができますね!