Streamlit in SnowflakeでCortexと対話できるチャットアプリを作ってみた

# はじめに

先日[SnowflakeでサポートされているStreamlitのバージョンがv1.26.0まで上がり](https://docs.snowflake.com/en/release-notes/2024/other/2024-03-15)、それに伴ってStreamlitのチャット機能がStreamlit in Snowflake（SiS）でも使えるようになりました。

Snowflakeでは生成AIの機能であるCortex LLMも一部リージョンではpublic previewになっているため、これらを組み合わせてチャットアプリを作ってみました。


# Snowflake Cortexとは

Snowflake上から機械学習や生成AIを使える機能で、MLベースのモデルやLLMベースのモデルを利用できます。

LLMベースのモデルでは以下の関数を利用できます。

- **COMPLETE**: プロンプトが与えられた場合、プロンプトに対応する応答を返す
- **EXTRACT_ANSWER**： ドキュメント（英語のテキストかJSONデータ）と質問が与えられると、その答えを返す
- **SENTIMENT**: 与えられたテキストから検出された肯定的または否定的なセンチメントを、-1から1までのスコアとして表す
- **SUMMARIZE**: 指定されたテキストを要約する
- **TRANSLATE**: 指定されたテキストを翻訳する

https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions

2024年3月28日現在はAWSとAzureの一部リージョンでのみ利用可能です。


# 検証環境
今回の検証は以下のSnowflakeアカウントで行いました。
- リージョン：US East (N. Virginia)
- エディション：Enterprise

またCortexのLLM関数はSnowpark ML v1.1.2 以降で使用できるので、Streamlitアプリを作ったら、まずはSnowpark MLを使うためにsnowflake-ml-pythonパッケージをインストールする必要があります。


# アプリ概要

今回はCortex LLMの関数の中でもCOMPLETE・TRANSLATE・SUMMARIZEを利用し、対話形式での応答・翻訳・要約の3つの機能を持ったアプリを作成しました。

アプリのUIは下記のようになっています。

- 「対話」画面
![スクリーンショット 2024-03-27 150140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/7247124e-c0d6-72b4-6b58-1e9dd2095600.png)

- 「翻訳」画面
![スクリーンショット 2024-03-27 154607.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/ddd60cdf-16d6-0b99-23f1-bfb7b24ad552.png)

- 「要約」画面
![スクリーンショット 2024-03-27 154627.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/7c59f1db-867d-75fe-2eec-680fcf8e59cb.png)


# 機能紹介

それぞれの機能について、動作やソースコードについて紹介します。


## 共通部分

インポート部分ではstreamlitとcortexの必要な関数のみインポートしています。

```python
import streamlit as st
from snowflake.cortex import Complete, Summarize, Translate
```

画面の描画部分のソースコードは下記のようになっています。
サイドメニューで利用したいAIモデルや機能を選択し、それに伴って呼び出す関数が替わり、メインコンテンツの描画が切り替わるようにしています。

```python
with st.sidebar:
    st.title("AI Bot")
    
    # 現状CortexだけだがGPT-4やClaude3も追加予定
    api_model = st.radio(
        "使用したいAIモデルを選んでください",
        ["Cortex"],
        horizontal=True
    )
    llm_func = st.radio(
        "使用したい機能を選んでください",
        ["対話", "翻訳", "要約"],
        horizontal=True
    )
    if llm_func == "対話":
        lang_model = st.radio(
            "使用したい言語モデルを選んでください",
            ("mistral-large", "mixtral-8x7b", "llama2-70b-chat", "mistral-7b", "gemma-7b")
        )

st.header(f"{llm_func}")

if llm_func == "対話":
    chat(lang_model)
elif llm_func == "翻訳":
    translate_any_to_any()
elif llm_func == "要約":
    summarize_any_to_ja()
```


## 機能① 対話

対話による応答では、ChatGPTのようにユーザーがプロンプトを入力するとそれに対応する応答を返します。

![SiS_Cortex_Chat.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/0a597b49-a38c-1d6a-4d3d-57688969f2a6.gif)


対話関数のソースコードは下記のようになっています。

```python
def chat(lang_model):
    if "messages" not in st.session_state:
        st.session_state.messages = []
    
    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])
    
    if prompt := st.chat_input("文章を入力してください。"):
        with st.chat_message("user"):
            st.markdown(prompt)
        st.session_state.messages.append({"role": "user", "content": prompt})

        response = Complete(lang_model, prompt)
        
        with st.chat_message("assistant"):
            st.markdown(response)
        st.session_state.messages.append({"role": "assistant", "content": response})
```

Cortex LLMのComplete関数に、言語モデルとユーザから入力されたプロンプトを渡すことで応答を生成しています。
プロンプトとCortexが生成した応答をsession_stateのmessagesにappendし、それをアイコンを加えて順に表示するという処理をしています。

現在Complete関数は、Pythonではマルチメッセージには対応していないので、1つのメッセージに対する応答を返すだけしかできないようです。

> The advanced chat-style (multi-message) form of COMPLETE is not currently supported in Python.

https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions#using-snowflake-cortex-llm-functions-with-python

## 機能② 翻訳

翻訳では、翻訳したい言語とテキストを入力すると、翻訳して返します。
下記のデモではスティーブジョブズのスタンフォード大学卒業式のスピーチを英語から日本語に翻訳し、その逆や、韓国語、ロシア語などへの翻訳も行えることを確認しています。

引用: https://english-club.jp/blog/jobs-speech-english-1/

![SiS_Cortex_Translate.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/db32f52c-9824-000c-8577-f1408d7e36af.gif)


翻訳関数のソースコードは下記のようになっています。

```python
def translate_any_to_any():
    col1, col2 = st.columns(2)
    with col1:
        st.write("翻訳したいテキスト")
        translate_from = st.selectbox(
            "",
            list(languages),
            key="translate_from",
            label_visibility="collapsed",
            index=1
        )
        txt = st.text_area(
            "翻訳したいテキスト",
            height=300,
            label_visibility="collapsed"
        )
    with col2:
        st.write("翻訳後のテキスト")
        translate_to = st.selectbox(
            "",
            list(languages),
            key="translate_to",
            label_visibility="collapsed"
        )
        response = ""
        if len(txt) > 0:
            response = Translate(
                txt,
                languages[translate_from],
                languages[translate_to]
            )
        if len(response) > 0:
            st.write(response)
```

また、Cortex LLMで利用できる11の言語を下記のように変数として定義しています。これは要約の関数でも利用するのでグローバル変数として定義しています。

```python
languages = {
    "日本語": "ja",
    "英語": "en",
    "フランス語": "fn",
    "ドイツ語": "de",
    "イタリア語": "it",
    "韓国語": "ko",
    "ポーランド語": "pl",
    "ポルトガル語": "pt",
    "ロシア語": "ru",
    "スペイン語": "es",
    "スウェーデン語": "sv",
}
```

## 機能③ 要約

要約では、要約したいテキストとその言語を入力すると、要約したテキストを返します。
下記のデモでは[Snowflakeの公式ドキュメント](https://docs.snowflake.com/ja/user-guide/intro-key-concepts)にある文章を入力として与えており、要約できることを確認しています。

Summarize関数は現時点ではまだ日本語をそのまま要約することはできなかったため、日本語のテキストが入力された場合は、①Translate関数で英語に変換 → ②Summarize関数で要約 → ③Translate関数で日本語に変換 という工夫を加えて要約を実現しています。

現状、Snowflake上でテキストの言語を判定することは難しそうなので、手間ですがユーザに要約したいテキストの言語も入力してもらう仕様としています。

![SiS_Cortex_Summarize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/b3496f72-0b07-92aa-f2c0-285274a412a3.gif)

要約関数のソースコードは下記のようになっています。

```python
def summarize_any_to_ja():
    col1, col2 = st.columns(2)
    with col1:
        st.write("要約したいテキスト")
        summarize_from = st.selectbox(
            "",
            list(languages),
            key="summarize_from",
            label_visibility="collapsed"
        )
        txt = st.text_area(
            "要約したい言語・テキスト",
            height=300,
            label_visibility="collapsed"
        )
    with col2:
        st.write("要約後のテキスト")
        response = ""
        if len(txt) > 0:
            en_txt = Translate(
                txt,
                languages[summarize_from],
                "en"
            )
            summarized_txt = Summarize(en_txt)
            response = Translate(summarized_txt, "en", "ja")
        if len(response) > 0:
            st.write(response)
    col3, col4 = st.columns(2)
    with col3:
        st.caption(f"{len(txt)} 文字")
    with col4:
        st.caption(f"{len(response)} 文字")
```


# 感想

今回はStreamlit in SnowflakeでCortexと対話できるチャットアプリ作りました。

個人的にはこれまでStreamlitをちゃんと触る機会はなかったので、実際に手を動かしてみて、「めちゃくちゃ簡単に実装できるな」という感想を持ちました。pythonコードの中に`st.~~~`といった記述を追加するだけで簡単にUIコンポーネントを追加できるのはとても楽だと感じました。
しかしSiSでサポートされるStreamlitのバージョンはネイティブのStreamlitに対して若干遅れて実装されるので、サポートバージョンが上がればよりリッチなUIを実装できると思いました。（例：`st.write_stream`でストリーム的にAIによる応答を表示するなど）

Cortexに関しても、使いたい関数をインポートして呼び出すだけでAIの機能を利用できるのは簡単すぎて驚きました。
現在はまだCortexの関数では使える言語の制限があり、日本語の入力に対応しようとすると余計な処理を挟まなくてはいけない場合があるので、そこが改善したらより簡単に実装できるだろうなと思いました。


# 今後の展望

今回の実装では、使えるAIモデルはCortexのみとしました。
しかし先日Claude3が発表されたので、Snowflake上からClaude3を使えるようにして、利用するAIモデルを複数（Cortex・Claude3・GPT-4など）から選択できるようにしたら面白いだろうなと考えています。
翻訳の機能ではDeepLやGoogle翻訳のAPIを使って比較もできそうですね。
それらの検証に関しては次の記事で書ければと思います。


# 仲間募集

NTTデータ テクノロジーコンサルティング事業本部 では、以下の職種を募集しています。

<details><summary>1. クラウド技術を活用したデータ分析プラットフォームの開発・構築(ITアーキテクト/クラウドエンジニア)</summary>

クラウド／プラットフォーム技術の知見に基づき、DWH、BI、ETL領域におけるソリューション開発を推進します。
https://enterprise-aiiot.nttdata.com/recruitment/career_sp/cloud_engineer
</details>


<details><summary>2. データサイエンス領域（データサイエンティスト／データアナリスト）</summary>

データ活用／情報処理／AI／BI／統計学などの情報科学を活用し、よりデータサイエンスの観点から、データ分析プロジェクトのリーダーとしてお客様のDX／デジタルサクセスを推進します。
https://enterprise-aiiot.nttdata.com/recruitment/career_sp/datascientist
</details>


<details><summary>3. お客様のAI活用の成功を推進するAIサクセスマネージャー</summary>

DataRobotをはじめとしたAIソリューションやサービスを使って、
お客様のAIプロジェクトを成功させ、ビジネス価値を創出するための活動を実施し、
お客様内でのAI活用を拡大、NTTデータが提供するAIソリューションの利用継続を推進していただく人材を募集しています。
https://nttdata.jposting.net/u/job.phtml?job_code=804
</details>


<details><summary>4. DX／デジタルサクセスを推進するデータサイエンティスト《管理職/管理職候補》</summary>

データ分析プロジェクトのリーダとして、正確な課題の把握、適切な評価指標の設定、分析計画策定や適切な分析手法や技術の評価・選定といったデータ活用の具現化、高度化を行い分析結果の見える化・お客様の納得感醸成を行うことで、ビジネス成果・価値を出すアクションへとつなげることができるデータサイエンティスト人材を募集しています。
https://nttdata.jposting.net/u/job.phtml?job_code=898
</details>


# ソリューション紹介

<details><summary>Trusted Data Foundationについて</summary>

～データ資産を分析活用するための環境をオールインワンで提供するソリューション～
https://enterprise-aiiot.nttdata.com/tdf/
最新のクラウド技術を採用して弊社が独自に設計したリファレンスアーキテクチャ（Datalake+DWH+AI/BI）を顧客要件に合わせてカスタマイズして提供します。
可視化、機械学習、DeepLearningなどデータ資産を分析活用するための環境がオールインワンで用意されており、これまでとは別次元の量と質のデータを用いてアジリティ高くDX推進を実現できます。
</details>


<details><summary>TDFⓇ-AM（Trusted Data Foundation - Analytics Managed Service）について</summary>

～データ活用基盤の段階的な拡張支援（Quick Start) と保守運用のマネジメント（Analytics Managed）をご提供することでお客様のDXを成功に導く、データ活用プラットフォームサービス～
https://enterprise-aiiot.nttdata.com/service/tdf/tdf_am
TDFⓇ-AMは、データ活用をQuickに始めることができ、データ活用の成熟度に応じて段階的に環境を拡張します。プラットフォームの保守運用はNTTデータが一括で実施し、お客様は成果創出に専念することが可能です。また、日々最新のテクノロジーをキャッチアップし、常に活用しやすい環境を提供します。なお、ご要望に応じて上流のコンサルティングフェーズからAI/BIなどのデータ活用支援に至るまで、End to Endで課題解決に向けて伴走することも可能です。
</details>


<details><summary>NTTデータとTableauについて</summary>

ビジュアル分析プラットフォームのTableauと2014年にパートナー契約を締結し、自社の経営ダッシュボード基盤への採用や独自のコンピテンシーセンターの設置などの取り組みを進めてきました。さらに2019年度にはSalesforceとワンストップでのサービスを提供開始するなど、積極的にビジネスを展開しています。

これまでPartner of the Year, Japanを4年連続で受賞しており、2021年にはアジア太平洋地域で最もビジネスに貢献したパートナーとして表彰されました。
また、2020年度からは、Tableauを活用したデータ活用促進のコンサルティングや導入サービスの他、AI活用やデータマネジメント整備など、お客さまの企業全体のデータ活用民主化を成功させるためのノウハウ・方法論を体系化した「デジタルサクセス」プログラムを提供開始しています。
https://enterprise-aiiot.nttdata.com/service/tableau
</details>


<details><summary>NTTデータとAlteryxについて</summary>

Alteryxは、業務ユーザーからIT部門まで誰でも使えるセルフサービス分析プラットフォームです。
Alteryx導入の豊富な実績を持つNTTデータは、最高位にあたるAlteryx Premiumパートナーとしてお客さまをご支援します。

導入時のプロフェッショナル支援など独自メニューを整備し、特定の業種によらない多くのお客さまに、Alteryxを活用したサービスの強化・拡充を提供します。

https://enterprise-aiiot.nttdata.com/service/alteryx
</details>


<details><summary>NTTデータとDataRobotについて</summary>

DataRobotは、包括的なAIライフサイクルプラットフォームです。
NTTデータはDataRobot社と戦略的資本業務提携を行い、経験豊富なデータサイエンティストがAI・データ活用を起点にお客様のビジネスにおける価値創出をご支援します。

https://enterprise-aiiot.nttdata.com/service/datarobot
</details>


<details><summary>NTTデータとInformaticaについて</summary>

データ連携や処理方式を専門領域として10年以上取り組んできたプロ集団であるNTTデータは、データマネジメント領域でグローバルでの高い評価を得ているInformatica社とパートナーシップを結び、サービス強化を推進しています。
https://enterprise-aiiot.nttdata.com/service/informatica
</details>


<details><summary>NTTデータとSnowflakeについて</summary>

NTTデータでは、Snowflake Inc.とソリューションパートナー契約を締結し、クラウド・データプラットフォーム「Snowflake」の導入・構築、および活用支援を開始しています。
NTTデータではこれまでも、独自ノウハウに基づき、ビッグデータ・AIなど領域に係る市場競争力のあるさまざまなソリューションパートナーとともにエコシステムを形成し、お客さまのビジネス変革を導いてきました。
Snowflakeは、これら先端テクノロジーとのエコシステムの形成に強みがあり、NTTデータはこれらを組み合わせることでお客さまに最適なインテグレーションをご提供いたします。

https://enterprise-aiiot.nttdata.com/service/snowflake
</details>