こちらの続編。気づいたらchainlit-0.6.2になっていました。
以前は、漢字の候補を確定するたびにメッセージが送信されていたのに困ってたのですが、それも改善されています。
langchainもアップグレードしろと言われました。
pip install -U chainlit
pip install langchain --upgrade
あと、古い設定ファイルがあるとエラーになるので、.chainlit/config.toml
を削除します。
そして、新たな概念としてAsync / Syncという考え方が導入されていました。要は非同期プログラミング。非同期型の関数を定義することで、他のタスクを実行しながらも処理を行うことができます。
以下のようにasync
キーワードを指定して関数を定義することで非同期実行されるようになります。
async def my_async_function():
# Your async code goes here
非同期関数を呼び出す際にはawait
キーワードを指定します。
async def another_async_function():
result = await my_async_function()
これで、以前の関数も動くようにはなったのですが、前は表示されていたローディング画像が表示されず、いかにも同期型の実行な感じが。
そして、マニュアルを読み進めていくと、Long running synchronous tasksという項目が。同期型で実行される関数がある場合には、chainlitのmake_async
関数を使うことで非同期型にすることができるとのこと。
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のモデルサービングエンドポイントを呼び出していたコードを以下のように変更。
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()