Web プロジェクトをすばやくビルドする

序章

プロジェクトの初期段階で Vue や React などを導入して複雑さを増したり、ページ レイアウトやインタラクションを実現するために CSS や JS に多くの時間を費やしたくありません。デモレベルのユースケースをすばやく構築できますか?

streamlit を試すことができます. しばらく使用した後, 良いツールだと思います. まあ, オープンソースです: https://github.com/streamlit/streamlit

さらに、商品化は気分が良く、コミュニティはより活発で、利用可能なコンポーネントはより豊富です.

8c08e241ebdcf2051a53a344bbc497e0.png

この記事では、最初に Streamlit の基本的な使用方法を紹介し、次にログインと登録の実装方法について説明し、最後に、私が見た Streamlit の欠点について説明します。

ストリームリットを実行する

Streamlit 独自のポジショニングは、データ サイエンティスト向けの Web プロトタイピング ツールです. Streamlit を介して、モデルやさまざまなデータ分析レポートをすばやく起動できます。

ここでは、streamlit のチュートリアル ドキュメントに基づいて、streamlit の基本的な使用方法を理解します. 実際には、これはこの記事の焦点では​​ありませんが、記事の完全性のために、追加させてください.

まず、streamlit をインストールする必要があります。

pip install streamlit

streamlit には多くの依存関係があるため、仮想環境で実行することをお勧めします。

インストール後、最初に hello world を作成し、hello.py ファイルを作成できます。コードは次のとおりです。

import streamlit as st

st.title('Hello World!')

実行:

streamlit run hello.py

効果は次のとおりです。

09786d0bc5f710729a4114046acffabd.png

Streamlit は、美しいページを開発するための多くのコンポーネントを提供します. 使用方法については、streamlit のドキュメントが既によく書かれています. ここでこれについて議論するのにそれほど時間はかかりません. ドキュメントを読むだけです: https://docs. streamlit.io/library/get-started/create-an-app.

この記事では、主にドキュメントに記載されていないことについて説明します。

ストリームリットはどのように始まりますか?

streamlit の実行モードは、streamlit run xxx.py の形式を使用することですが、ドキュメントを読むと、python -m streamlit run xxx.py の形式もサポートしていることがわかりました。

コントロール感が弱い気がするのですが、ストリームリットの実行コマンドはどのように動作しますか?

streamlit ソース コードをプルダウンし、setup.py ファイルの entry_points 構成を確認します。

538f11d1e83a3b1ac9f698b10419b3d7.png

上の図からわかるように、streamlit コマンドの機能は、streamlit/web/cli.py の main() メソッドから取得されます。

71b5f0470bb79e2b6b6e98a27d975201.png

クリック ライブラリを使用してコマンド パラメーターを受け取る. 率直に言うと、クリック ライブラリがコマンド ライン パラメーターを受け取る方法は、Python のネイティブ argparse よりもはるかに洗練されていると思います。

cli.py のコードを読むだけで、streamlit が tornado に基づいて開発されており、tornado.httpserve を Web バックエンドとして使用していることがわかります。

2cd45ca9372bdfff85f166150c80a45e.png

Tornado は Python の古い Web フレームワークです. 当時は python asyncio がまだ成熟していませんでした. 高性能な Web フレームワークを得るために, tornado は Linux epoll と BSD kqueue に基づく高性能な非同期 io とそのソースを実現しました.コードは複雑で難しかったです。

コードを読むと、streamlit は最初に index.html をロードし、次にページ ロジックを index.html (つまり、streamlit によって提供されるコンポーネントを使用して作成されたページ) に埋め込むことがわかります。 id が root である div 要素。

6999cf8130fe089957f62ca5bd331dfb.png

これがストリームリットの基本的なプロセスです。

streamlit フラグを削除する

hello.py を実装して実行すると、次の図に示すように、streamlit の多くの機能があることがわかります。

b60866e0a851aeee16a08607b8aa​​077e.png

上の図からわかるように、streamlit では、設定、リロード、および streamlit の公式 Web サイトへのアクセスの操作が提供されます。また、streamlit は、タイトルとフッターに独自の streamlit ロゴを追加しました。

独自の Web アプリを立ち上げる必要がある場合、もちろん、ユーザーに多くの操作を行わせたくありません。また、競合他社に、私が streamlit を使用していることを一目で見られたくありません。

解決策は、これらのコンテンツを非表示にすることです. [streamlit hiddle xxx] を検索すると、次の解決策が見つかります: https://discuss.streamlit.io/t/remove-made-with-streamlit-from-bottom-of -app/1370/2、関連するコードは次のとおりです。

hide_streamlit_style = """
            <style>
            #MainMenu {visibility: hidden;}
            footer {visibility: hidden;}
            </style>
            """
st.markdown(hide_streamlit_style, unsafe_allow_html=True)

原理は非常に単純で、st の markdown メソッドを使用して html コードを実行し、css を使用してこれらを非表示にします。

残念ながら、この効果は良くありません. streamlit が読み込まれると、最初に独自の html と js が読み込まれ、次にロジックが読み込まれます. ネットワークが貧弱な場合、メニューとフッターがしばらく表示され、その後 css が非表示になります. .

また、ユーザーがページ上のボタンをクリックするなどの操作を行うたびに、streamlit はページをリロードします. これはまだ古いプロセスです. 最初に独自の html, css, js をロードし、次にあなたのものをロードします. 操作ごとに,メニューとフッターがページに表示されますが、これは欺瞞的です。

もちろん、最善の方法は、streamlit のソース コードを直接変更し、不要な部分をすべて削除することです。

streamlit のソース コードを読むと、streamlit のフロント エンドは React によって実装されていることがわかります. Python ライブラリとしてリリースされる場合、React によって実装されたコードは webpack によってパッケージ化されます. ソース コードを変更する場合は、 React コードを変更してから、パッケージ化と公開のプロセスを自分で行う必要があります。

うーん、ちょっとコストが高いし、自分で改造するとあとでストリームリットの新機能に対応するのが難しくなるので、単純に考えてハードリプレイスという方法でやってみようと思います。

init_streamlit.py を作成し、次のコードを記述します。

import pathlib
import os
from bs4 import BeautifulSoup
from shutil import copyfile

from configs import ROOT_PATH


def modify_title_str(soup, title):
    """
    修改 index.html 的 title
    """
    soup.title.string = title
    return soup


def add_js_code(soup, js_code):
    """
    添加 js code 到 index.html 中
    """
    script_tag = soup.find(id='custom-js')
    if not script_tag:
        script_tag = soup.new_tag("script", id='custom-js')
    # custom-js script 中的 js code
    script_tag.string = js_code
    # 向 body 节点中添加内容
    soup.body.append(script_tag)
    return soup


def replace_favicon(streamlit_model_path):
    """替换streamlit的icon"""
    logo_path = os.path.join(streamlit_model_path, 'static', 'favicon.png')
    # 删除 logo
    pathlib.Path(logo_path).unlink()
    copyfile(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'favicon.png'), logo_path)


def init_streamlit(streamlit_model_path, title, footer):
    index_path = pathlib.Path(streamlit_model_path) / "static" / "index.html"

    soup = BeautifulSoup(index_path.read_text(encoding='utf-8'), features="lxml")

    soup = modify_title_str(soup, title)
    js_code = f'''
    document.querySelector("#MainMenu").style.visibility = 'hidden'
    document.querySelector('footer').innerHTML = '{footer}'
    '''
    soup = add_js_code(soup, js_code)
    index_path.write_text(str(soup), encoding='utf-8')


streamlit_model_path = os.path.join(ROOT_PATH, 'venv\\lib\\site-packages\\streamlit')
init_streamlit(streamlit_model_path=streamlit_model_path, title='懒编程', footer='Copyright © 2022, ayuliao Inc.')

上記のコードは主に、タイトル、フッターなど、streamlit の index.html の関連要素を置き換えることです。index.html を直接変更して、streamlit の関連情報を非表示にする効果を達成し、streamlit がその要素を読み込まないようにします。独自の html を最初に js に配置すると、これらの要素をうまく隠せないという問題があります。

また、index.html のタイトルを変更するだけでは効果がありません.なぜなら、index.html のタイトルも streamlit 自体の js メソッドによって変更されるからです.この問題を解決するには、hello.py ファイルを変更します.コードは次のとおりです。

import init_streamlit
import streamlit as st

st.set_page_config(page_title='懒编程',
                   page_icon='logo.jpg')

st.title('hello world')

hello.py を実行すると、結果は次の図のようになります。

72ac2957d5ad087a61145384a5d28f10.png

ログインと登録を実現

ログインと登録の実装方法も、ドキュメントには記載されていません。

Streamlit 自体の位置付けにも関係するかもしれませんが、Streamlit 自体はログインや登録などの機能を提供していないため、ログインや登録を実現するには、自分で作成し、Streamlit プラグインの形で実装する必要があります。

streamlit には優れた streamlit プラグインを提供するプラグイン ページがあります. streamlit プラグインのフロントエンドのほとんどは React を使用して独自に実装されていますが、React は streamlit が提供するメソッドを使用して streamlit プラグインの目的を達成します。挿入。

もちろん、いくつかの単純なプラグインは、ログインおよび登録プラグインの場合のように、必ずしも React 開発ページと対話する必要はありません。

検索した結果、pip を介してインストールおよび使用できる Streamlit-Authenticator プラグイン (https://github.com/mkhorasani/Streamlit-Authenticator) を見つけました。

pip install streamlit-authenticator

streamlit-authenticator が提供する機能は単純すぎるため、データベースを通じてユーザー情報を記録せず、ほとんどの場合、満足できないため、魔法のような変更を加える必要があります。

streamlit-authenticator のソース コードを正常に実行するには、関連する依存関係をインストールする必要がありますが、streamlit-authenticator は requirements.txt ファイルを提供しませんが、その setup.py は依存関係を提供します。セットアップの情報に基づいて自分で行うことができます。 py インストールするか、私のような怠惰な方法を使用して、最初に streamlit-authenticator をインストールし、次に個別に削除して、関連する依存関係がインストールされるようにします。

libs フォルダーに streamlit-authenticator 関連のコードを配置します。

streamlit-authenticator はもともと yaml 設定ファイルを介してログインと登録を実装していましたが、sqllite を使用するように変更しました. もちろん、MySQL などに変更することもできます. さらに、招待コードのロジックを追加しました. ここでは、いくつかの招待コードをハードコードしました. これらの招待コードを持つユーザーのみが登録でき、登録されたユーザーはログインできます.

変更された streamlit-authenticator と連携するために、models ディレクトリを作成し、関連する SQL ロジックをそこに記述しました。

まあ、これは複雑ではありませんが、変更のロジックがたくさんあるので、言葉では説明しません. 記事の最後に戻って、プロジェクトコードを見てください.

streamlit の更新メカニズム (ページでボタンが操作されるたびにページが更新される) のために、ログイン、登録、およびログイン ページを合理的に整理する方法にも落とし穴があります。

Streamlit 公式ドキュメントのマルチページ アプリの内容を見ると、レイアウトが非常に硬直的で見苦しいことがわかります. 簡単な実験と調査の後、タブ コンポーネントを使用して最終的なレイアウトを実現しました. 関連するコード以下のとおりであります:

import os
import yaml
import init_streamlit
import streamlit as st
import libs.streamlit_authenticator as stauth

st.set_page_config(page_title='懒编程',
                   page_icon='logo.jpg')

st.title('hello world')


def init_authenticator():
    filepath = os.path.abspath(os.path.dirname(__file__))
    with open(os.path.join(filepath, 'auth.yaml')) as file:
        config = yaml.load(file, Loader=stauth.SafeLoader)

    authenticator = stauth.Authenticate(
        config['credentials'],
        config['cookie']['name'],
        config['cookie']['key'],
        config['cookie']['expiry_days'],
    )
    return authenticator


def register_user(authenticator):
    try:
        if authenticator.register_user('Register user', preauthorization=False):
            st.success('User registered successfully')
    except Exception as e:
        st.error(e)


def my_logics():
    st.markdown('login success')


def start_web():
    authenticator = init_authenticator()
    # check cookie not login again
    authenticator._check_cookie()
    if st.session_state["authentication_status"]:
        authenticator.logout('Logout', 'sidebar')
        my_logics()
    else:

        tab1, tab2 = st.tabs(["Login", "Register"])
        with tab1:
            name, authentication_status, username = authenticator.login(
                'Login', 'main')
            if st.session_state["authentication_status"] == False:
                st.error('Username/password is incorrect')
            elif st.session_state["authentication_status"] == None:
                st.warning('Please enter your username and password')
        with tab2:
            register_user(authenticator)

start_web()

ログインページ:

6b767f9a3b0f78cb1f1138677b2d11fd.png

登録ページ:

0d6120f9951bb9e8f3f3e684922977b9.png

ログイン成功後のホームページ:

13cc8c9a2c3ee49c250062db6c3113a9.png

終わり

streamlit を使用すると、他の人に見せることができる Web デモをすばやく構築できますが、streamlit には、Flask や Fastapi などのフレームワークなど、リクエストを区別する機能がないという比較的大きな欠点もあります。異なるリクエストを区別できますが、streamlit は機能しません. 複数人で使用すると、他の人がページを操作しているときに、現在のページも影響を受ける可能性があるように見えます.

さて、これは、この記事の関連コード github である streamlit に関連するプラクティスです: https://github.com/ayuLiao/learn-streamlit

Erliang です。次の記事でお会いしましょう。

おすすめ

転載: blog.csdn.net/weixin_30230009/article/details/126684850