Chainlit 0.6.2に移行してみる

こちらの続編。気づいたらchainlit-0.6.2になっていました。

https://qiita.com/taka_yayoi/items/3afeea6edb4f1eb022b4

https://qiita.com/taka_yayoi/items/ccdcde287594d75672cd

以前は、漢字の候補を確定するたびにメッセージが送信されていたのに困ってたのですが、それも改善されています。

langchainもアップグレードしろと言われました。

```
pip install -U chainlit
```
```
pip install langchain --upgrade
```

あと、古い設定ファイルがあるとエラーになるので、`.chainlit/config.toml`を削除します。

そして、新たな概念として**Async / Sync**という考え方が導入されていました。要は非同期プログラミング。非同期型の関数を定義することで、他のタスクを実行しながらも処理を行うことができます。

https://docs.chainlit.io/guides/sync-async

以下のように`async`キーワードを指定して関数を定義することで非同期実行されるようになります。

```py
async def my_async_function():
    # Your async code goes here
```

非同期関数を呼び出す際には`await`キーワードを指定します。

```py
async def another_async_function():
    result = await my_async_function()
```

これで、以前の関数も動くようにはなったのですが、前は表示されていたローディング画像が表示されず、いかにも同期型の実行な感じが。

そして、マニュアルを読み進めていくと、**Long running synchronous tasks**という項目が。同期型で実行される関数がある場合には、chainlitの`make_async`関数を使うことで非同期型にすることができるとのこと。

```py
from chainlit import make_async

def my_sync_function():
    # Your synchronous code goes here
    import time
    time.sleep(10)
    return 0

async_function = make_async(my_sync_function)

async def main():
    result = await async_function()
```

そういう訳で、以前Databricksのモデルサービングエンドポイントを呼び出していたコードを以下のように変更。

```py
import os
from langchain import PromptTemplate, OpenAI, LLMChain
import chainlit as cl
from chainlit import on_message
from chainlit import make_async

import os
import requests
import numpy as np
import pandas as pd

import json

def create_tf_serving_json(data):
    return {
        "inputs": {name: data[name].tolist() for name in data.keys()}
        if isinstance(data, dict)
        else data.tolist()
    }


def score_model(question):
  # 1. パーソナルアクセストークンを設定してください
  token = "<パーソナルアクセストークン>" 

  # 2. モデルエンドポイントのURLを設定してください
  url = "<エンドポイントのURL>"

  headers = {'Authorization': f'Bearer {token}',
             "Content-Type": "application/json",}

  dataset = pd.DataFrame({'question':[question]})

  ds_dict = (
        {"dataframe_split": dataset.to_dict(orient="split")}
        if isinstance(dataset, pd.DataFrame)
        else create_tf_serving_json(dataset)
    )
  data_json = json.dumps(ds_dict, allow_nan=True)
  response = requests.request(method="POST", headers=headers, url=url, data=data_json)
  if response.status_code != 200:
    raise Exception(
       f"Request failed with status {response.status_code}, {response.text}"
    )
  
  return response.json()

# 同期型関数を非同期型関数に
# https://docs.chainlit.io/guides/sync-async
async_score_model = make_async(score_model)

@cl.on_message  # this function will be called every time a user inputs a message in the UI
async def main(message: str):

    response = await async_score_model(message)

    answer = response['predictions'][0]["answer"]
    source = response['predictions'][0]["source"]

    # Send a response back to the user
    await cl.Message(
        content=f"{answer}\n\nソース: {source}",
    ).send()
```

これでローディング画像も表示されるようになりました！
![Screenshot 2023-08-11 at 17.57.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d86af069-8ec0-b1a0-f76d-ee39269f2201.png)
![Screenshot 2023-08-11 at 17.58.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/961a8e90-a3b7-c61f-16e4-f476b7ea775f.png)

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)