ローカルLLMメッセンジャー:iPhoneでGenAIとチャット

この AI/ML ハッカソンの投稿では、昨年の Docker AI/ML ハッカソンで優勝した別のプロジェクトを共有したいと思います。 今回は、 Justin Garrison 氏が作成した特別賞受賞者である Local LLM Messenger に飛び込みます。

開発者は、人工知能 (AI) の力をすべての人に届けるために、限界を押し広げています。 エキサイティングなアプローチの 1 つは、大規模言語モデル (LLM) を Slack や iMessage などの使い慣れたメッセージング プラットフォームと統合することです。 これは利便性だけではありません。これらのプラットフォームを、強力なAIツールと対話するためのランチパッドに変えることです。

Ai/mlハッカソン

想像してみてください: 簡単なコード スニペットや、コーディングの問題に対する解決策をブレインストーミングするための支援が必要です。 メッセージングアプリにLLMが統合されているため、使い慣れたインターフェース内で直接AIアシスタントとチャットして、創造的なアイデアを生み出したり、解決策のブレーンストーミングを支援したりすることができます。 複雑なコマンドや不便なインターフェースはもう必要ありません - AIの力を解き放つための自然な会話だけです。

メッセージングプラットフォームとの統合は、特にmacOSユーザーにとっては時間のかかる作業です。 そこで、Local LLM Messenger(LoLLMM)の出番となり、iMessageを介してAIと接続するための合理化されたソリューションを提供します。 

LoLLM Messengerの特徴は何ですか?

次のデモは、AI/ML Hackathon に提出されたもので、LoLLM Messenger の概要を示しています (図 1)。

図 1: AI/ML Hackathonに提出されたLoLLM Messengerのデモ。

LoLLM Messengerボットを使用すると、コンピューター上で直接実行されているGenerative AI(GenAI)モデルにiMessageを送信できます。 このアプローチにより、複雑なセットアップやクラウドサービスが不要になり、開発者はローカルでLLMを簡単に試すことができます。

LoLLM Messengerの主な機能

LoLLM Messengerには、次のような同様のプロジェクトの中で際立った優れた機能が含まれています。

  • ローカル実行:コンピューター上で実行されるため、クラウドベースのサービスが不要になり、データのプライバシーが確保されます。
  • スケーラビリティ:複数のAIモデルを同時に処理するため、ユーザーはさまざまなモデルを試したり、モデルを簡単に切り替えたりすることができます。
  • ユーザーフレンドリーなインターフェース:シンプルで直感的なインターフェースを提供し、あらゆるスキルレベルのユーザーがアクセスできます。
  • Sendblueとの統合: Sendblueとシームレスに統合され、ユーザーはiMessageをボットに送信し、受信トレイで直接応答を受け取ることができます。
  • ChatGPTのサポート:GPT-3をサポートします。5 ターボとDALL-Eは 2 モデルで、ユーザーは強力なAI機能にアクセスできます。
  • カスタマイズ: ユーザーは、使用可能なコマンドを変更し、独自の AI モデルを統合することで、ボットの動作をカスタマイズできます。

それはどのように機能しますか?

図 2 に示すアーキテクチャ図は、LoLLM Messenger プロジェクト内のコンポーネントと相互作用の概要を示しています。 これは、メインアプリケーション、AIモデル、メッセージングプラットフォーム、および外部APIがどのように連携して、ユーザーがコンピューターで実行されているAIモデルにiMessageを送信できるようにするかを示しています。

lollmメッセンジャーのコンポーネントとプロセスを示す図(user、sendblue api、docker、aiモデルなど)。
図 2: LoLLM Messenger プロジェクトのコンポーネントとインタラクションの概要。

Docker、Sendblue、Ollamaを活用することで、LoLLM Messengerは、クラウドベースのサービスを必要とせずにAIモデルを探索したいユーザーにシームレスで効率的なソリューションを提供します。 LoLLM Messengerは 、Docker Compose を利用して必要なサービスを管理します。 

Docker Compose は、メイン アプリケーション、ngrok (安全なトンネルを作成するため)、Ollama (メッセージング アプリと AI モデルの間のギャップを埋めるサーバー) など、複数のコンテナーのセットアップと構成を処理することで、プロセスを簡素化します。

テクニカルスタック

LoLLM Messengerの技術スタックには、次のものが含まれます。

  • Lollmmサービス:このサービスは、メインアプリケーションの実行を担当します。 受信 iMessage を処理し、ユーザー要求を処理し、AI モデルと対話します。 lollmmサービスは、テキストと画像生成のための強力なAIモデルであるOllamaモデルと通信します。
  • Ngrok: このサービスは、ngrok を使用してメイン アプリケーションのポート 8000をインターネットに公開するために使用されます。Alpine イメージで実行され、ポート 8000 から ngrok トンネルにトラフィックを転送します。 サービスは、ホスト・ネットワーク・モードで実行されるように設定されています。
  • オラマ: このサービスは、テキストと画像の生成のための強力な AI モデルである Ollama モデルを実行します。 ポート 11434 でリッスンし、 ./run/ollama から /home/ollama までのボリュームをマウントします。 このサービスは GPU リソースを使用してデプロイするように設定されており、利用可能な場合は NVIDIA GPU を利用できるようにします。
  • センドブルー: このプロジェクトはSendblueと統合され、iMessageを処理します。 Sendblueを設定するには、APIキーとAPIシークレットをapp/.envに追加します ファイルを作成し、電話番号をSendblueの連絡先として追加します。

はじめ

開始するには、次のコンポーネントをインストールして設定していることを確認します。

リポジトリのクローンを作成する

ターミナル ウィンドウを開き、次のコマンドを実行して、このサンプル アプリケーションを複製します。

git clone https://github.com/dockersamples/local-llm-messenger

これで、 local-llm-messenger ディレクトリに次のファイルが作成されます。

.
├── LICENSE
├── README.md
├── app
│   ├── Dockerfile
│   ├── Pipfile
│   ├── Pipfile.lock
│   ├── default.ai
│   ├── log_conf.yaml
│   └── main.py
├── docker-compose.yaml
├── img
│   ├── banner.png
│   ├── lasers.gif
│   └── lollm-demo-1.gif
├── justfile
└── test
    ├── msg.json
    └── ollama.json

4 directories, 15 files

/appディレクトリの下にあるスクリプトmain.pyファイルは、FastAPIフレームワークを使用してAI搭載のメッセージングアプリケーション用のWebサーバーを作成するPythonスクリプトです。このスクリプトは、OpenAIのGPT-3 モデルとOllamaエンドポイントと対話して応答を生成します。 SendblueのAPIを使用してメッセージを送信します。

このスクリプトは、FastAPI、リクエスト、ロギング、その他の必要なモジュールなど、必要なライブラリを最初にインポートします。

from dotenv import load_dotenv
import os, requests, time, openai, json, logging
from pprint import pprint
from typing import Union, List

from fastapi import FastAPI
from pydantic import BaseModel

from sendblue import Sendblue

このセクションでは、API キー、コールバック URL、Ollama API エンドポイント、最大コンテキストと単語数の制限などの設定変数を設定します。

SENDBLUE_API_KEY = os.environ.get("SENDBLUE_API_KEY")
SENDBLUE_API_SECRET = os.environ.get("SENDBLUE_API_SECRET")
openai.api_key = os.environ.get("OPENAI_API_KEY")
OLLAMA_API = os.environ.get("OLLAMA_API_ENDPOINT", "http://ollama:11434/api")
# could also use request.headers.get('referer') to do dynamically
CALLBACK_URL = os.environ.get("CALLBACK_URL")
MAX_WORDS = os.environ.get("MAX_WORDS")

次に、スクリプトはログ設定を実行し、ログレベルを INFO に設定します。 app.log という名前のファイルにメッセージをログに記録するためのファイルハンドラを作成します。

次に、AI モデルとの対話、コンテキストの管理、メッセージの送信、コールバックの処理、スラッシュ コマンドの実行など、さまざまな関数を定義します。

def set_default_model(model: str):
    try:
        with open("default.ai", "w") as f:
            f.write(model)
            f.close()
            return
    except IOError:
        logger.error("Could not open file")
        exit(1)


def get_default_model() -> str:
    try:
        with open("default.ai") as f:
            default = f.readline().strip("\n")
            f.close()
            if default != "":
                return default
            else:
                set_default_model("llama2:latest")
                return ""
    except IOError:
        logger.error("Could not open file")
        exit(1)


def validate_model(model: str) -> bool:
    available_models = get_model_list()
    if model in available_models:
        return True
    else:
        return False


def get_ollama_model_list() -> List[str]:
    available_models = []
   
    tags = requests.get(OLLAMA_API + "/tags")
    all_models = json.loads(tags.text)
    for model in all_models["models"]:
        available_models.append(model["name"])
    return available_models


def get_openai_model_list() -> List[str]:
    return ["gpt-3.5-turbo", "dall-e-2"]


def get_model_list() -> List[str]:
    ollama_models = []
    openai_models = []
    all_models = []
    if "OPENAI_API_KEY" in os.environ:
        # print(openai.Model.list())
        openai_models = get_openai_model_list()

    ollama_models = get_ollama_model_list()
    all_models = ollama_models + openai_models
    return all_models


DEFAULT_MODEL = get_default_model()

if DEFAULT_MODEL == "":
    # This is probably the first run so we need to install a model
    if "OPENAI_API_KEY" in os.environ:
        print("No default model set. openai is enabled. using gpt-3.5-turbo")
        DEFAULT_MODEL = "gpt-3.5-turbo"
    else:
        print("No model found and openai not enabled. Installing llama2:latest")
        pull_data = '{"name": "llama2:latest","stream": false}'
        try:
            pull_resp = requests.post(OLLAMA_API + "/pull", data=pull_data)
            pull_resp.raise_for_status()
        except requests.exceptions.HTTPError as err:
            raise SystemExit(err)
        set_default_model("llama2:latest")
        DEFAULT_MODEL = "llama2:latest"


if validate_model(DEFAULT_MODEL):
    logger.info("Using model: " + DEFAULT_MODEL)
else:
    logger.error("Model " + DEFAULT_MODEL + " not available.")
    logger.info(get_model_list())

    pull_data = '{"name": "' + DEFAULT_MODEL + '","stream": false}'
    try:
        pull_resp = requests.post(OLLAMA_API + "/pull", data=pull_data)
        pull_resp.raise_for_status()
    except requests.exceptions.HTTPError as err:
        raise SystemExit(err)



def set_msg_send_style(received_msg: str):
    """Will return a style for the message to send based on matched words in received message"""
    celebration_match = ["happy"]
    shooting_star_match = ["star", "stars"]
    fireworks_match = ["celebrate", "firework"]
    lasers_match = ["cool", "lasers", "laser"]
    love_match = ["love"]
    confetti_match = ["yay"]
    balloons_match = ["party"]
    echo_match = ["what did you say"]
    invisible_match = ["quietly"]
    gentle_match = []
    loud_match = ["hear"]
    slam_match = []

    received_msg_lower = received_msg.lower()
    if any(x in received_msg_lower for x in celebration_match):
        return "celebration"
    elif any(x in received_msg_lower for x in shooting_star_match):
        return "shooting_star"
    elif any(x in received_msg_lower for x in fireworks_match):
        return "fireworks"
    elif any(x in received_msg_lower for x in lasers_match):
        return "lasers"
    elif any(x in received_msg_lower for x in love_match):
        return "love"
    elif any(x in received_msg_lower for x in confetti_match):
        return "confetti"
    elif any(x in received_msg_lower for x in balloons_match):
        return "balloons"
    elif any(x in received_msg_lower for x in echo_match):
        return "echo"
    elif any(x in received_msg_lower for x in invisible_match):
        return "invisible"
    elif any(x in received_msg_lower for x in gentle_match):
        return "gentle"
    elif any(x in received_msg_lower for x in loud_match):
        return "loud"
    elif any(x in received_msg_lower for x in slam_match):
        return "slam"
    else:
        return

MsgCallback の 2 つのクラスは、受信メッセージとコールバック データの構造を表すために定義されています。このコードには、デフォルトモデルの設定、モデルの検証、Sendblue APIとの対話、メッセージの処理など、メッセージングプラットフォームのさまざまな側面を処理するためのさまざまな関数とクラスも含まれています。 また、スラッシュ コマンドの処理、コンテキストからのメッセージの作成、ファイルへのコンテキストの追加を行う関数も含まれています。

class Msg(BaseModel):
    accountEmail: str
    content: str
    media_url: str
    is_outbound: bool
    status: str
    error_code: int | None = None
    error_message: str | None = None
    message_handle: str
    date_sent: str
    date_updated: str
    from_number: str
    number: str
    to_number: str
    was_downgraded: bool | None = None
    plan: str


class Callback(BaseModel):
    accountEmail: str
    content: str
    is_outbound: bool
    status: str
    error_code: int | None = None
    error_message: str | None = None
    message_handle: str
    date_sent: str
    date_updated: str
    from_number: str
    number: str
    to_number: str
    was_downgraded: bool | None = None
    plan: str



def msg_openai(msg: Msg, model="gpt-3.5-turbo"):
    """Sends a message to openai"""
    message_with_context = create_messages_from_context("openai")

    # Add the user's message and system context to the messages list
    messages = [
        {"role": "user", "content": msg.content},
        {"role": "system", "content": "You are an AI assistant. You will answer in haiku."},
    ]

    # Convert JSON strings to Python dictionaries and add them to messages
    messages.extend(
        [
            json.loads(line)  # Convert each JSON string back into a dictionary
            for line in message_with_context
        ]
    )

    # Send the messages to the OpenAI model
    gpt_resp = client.chat.completions.create(
        model=model,
        messages=messages,
    )

    # Append the system context to the context file
    append_context("system", gpt_resp.choices[0].message.content)

    # Send a message to the sender
    msg_response = sendblue.send_message(
        msg.from_number,
        {
            "content": gpt_resp.choices[0].message.content,
            "status_callback": CALLBACK_URL,
        },
    )
    
    return




def msg_ollama(msg: Msg, model=None):
    """Sends a message to the ollama endpoint"""
    if model is None:
        logger.error("Model is None when calling msg_ollama")
        return  # Optionally handle the case more gracefully

    ollama_headers = {"Content-Type": "application/json"}
    ollama_data = (
        '{"model":"' + model +
        '", "stream": false, "prompt":"' +
        msg.content +
        " in under " +
        str(MAX_WORDS) +  # Make sure MAX_WORDS is a string
        ' words"}'
    )
    ollama_resp = requests.post(
        OLLAMA_API + "/generate", headers=ollama_headers, data=ollama_data
    )
    response_dict = json.loads(ollama_resp.text)
    if ollama_resp.ok:
        send_style = set_msg_send_style(msg.content)
        append_context("system", response_dict["response"])
        msg_response = sendblue.send_message(
            msg.from_number,
            {
                "content": response_dict["response"],
                "status_callback": CALLBACK_URL,
                "send_style": send_style,
            },
        )
    else:
        msg_response = sendblue.send_message(
            msg.from_number,
            {
                "content": "I'm sorry, I had a problem processing that question. Please try again.",
                "status_callback": CALLBACK_URL,
            },
        )
    return

app/ディレクトリに移動し、環境変数を追加するための新しいファイルを作成します。

touch .env
SENDBLUE_API_KEY=your_sendblue_api_key
SENDBLUE_API_SECRET=your_sendblue_api_secret
OLLAMA_API_ENDPOINT=http://host.docker.internal:11434/api
OPENAI_API_KEY=your_openai_api_key

次に、ngrok authtoken を Docker Compose ファイルに追加します。 authtoken は、このリンクから取得できます。

services:
  lollm:
    build: ./app
    # command:
      # - sleep
      # - 1d
    ports:
      - 8000:8000
    env_file: ./app/.env
    volumes:
      - ./run/lollm:/run/lollm
    depends_on:
      - ollama
    restart: unless-stopped
    network_mode: "host"
  ngrok:
    image: ngrok/ngrok:alpine
    command:
      - "http"
      - "8000"
      - "--log"
      - "stdout"
    environment:
      - NGROK_AUTHTOKEN=2i6iXXXXXXXXhpqk1aY1
    network_mode: "host"
  ollama:
    image: ollama/ollama
    ports:
      - 11434:11434
    volumes:
      - ./run/ollama:/home/ollama
    network_mode: "host"

アプリケーションスタックの実行

次に、次のようにアプリケーション スタックを実行できます。

$ docker compose up

次のような出力が表示されます。

[+] Running 4/4
 ✔ Container local-llm-messenger-ollama-1                           Create...                                          0.0s
 ✔ Container local-llm-messenger-ngrok-1                            Created                                            0.0s
 ✔ Container local-llm-messenger-lollm-1                            Recreat...                                         0.1s
 ! lollm Published ports are discarded when using host network mode                                                    0.0s
Attaching to lollm-1, ngrok-1, ollama-1
ollama-1  | 2024/06/20 03:14:46 routes.go:1011: INFO server config env="map[OLLAMA_DEBUG:false OLLAMA_FLASH_ATTENTION:false OLLAMA_HOST:http://0.0.0.0:11434 OLLAMA_KEEP_ALIVE: OLLAMA_LLM_LIBRARY: OLLAMA_MAX_LOADED_MODELS:1 OLLAMA_MAX_QUEUE:512 OLLAMA_MAX_VRAM:0 OLLAMA_MODELS:/root/.ollama/models OLLAMA_NOHISTORY:false OLLAMA_NOPRUNE:false OLLAMA_NUM_PARALLEL:1 OLLAMA_ORIGINS:[http://localhost https://localhost http://localhost:* https://localhost:* http://127.0.0.1 https://127.0.0.1 http://127.0.0.1:* https://127.0.0.1:* http://0.0.0.0 https://0.0.0.0 http://0.0.0.0:* https://0.0.0.0:* app://* file://* tauri://*] OLLAMA_RUNNERS_DIR: OLLAMA_TMPDIR:]"
ollama-1  | time=2024-06-20T03:14:46.308Z level=INFO source=images.go:725 msg="total blobs: 0"
ollama-1  | time=2024-06-20T03:14:46.309Z level=INFO source=images.go:732 msg="total unused blobs removed: 0"
ollama-1  | time=2024-06-20T03:14:46.309Z level=INFO source=routes.go:1057 msg="Listening on [::]:11434 (version 0.1.44)"
ollama-1  | time=2024-06-20T03:14:46.309Z level=INFO source=payload.go:30 msg="extracting embedded files" dir=/tmp/ollama2210839504/runners
ngrok-1   | t=2024-06-20T03:14:46+0000 lvl=info msg="open config file" path=/var/lib/ngrok/ngrok.yml err=nil
ngrok-1   | t=2024-06-20T03:14:46+0000 lvl=info msg="open config file" path=/var/lib/ngrok/auth-config.yml err=nil
ngrok-1   | t=2024-06-20T03:14:46+0000 lvl=info msg="starting web service" obj=web addr=0.0.0.0:4040 allow_hosts=[]
ngrok-1   | t=2024-06-20T03:14:46+0000 lvl=info msg="client session established" obj=tunnels.session
ngrok-1   | t=2024-06-20T03:14:46+0000 lvl=info msg="tunnel session started" obj=tunnels.session
ngrok-1   | t=2024-06-20T03:14:46+0000 lvl=info msg="started tunnel" obj=tunnels name=command_line addr=http://localhost:8000 url=https://94e1-223-185-128-160.ngrok-free.app
ollama-1  | time=2024-06-20T03:14:48.602Z level=INFO source=payload.go:44 msg="Dynamic LLM libraries [cpu cuda_v11]"
ollama-1  | time=2024-06-20T03:14:48.603Z level=INFO source=types.go:71 msg="inference compute" id=0 library=cpu compute="" driver=0.0 name="" total="7.7 GiB" available="3.9 GiB"
lollm-1   | INFO:     Started server process [1]
lollm-1   | INFO:     Waiting for application startup.
lollm-1   | INFO:     Application startup complete.
lollm-1   | INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
ngrok-1   | t=2024-06-20T03:16:58+0000 lvl=info msg="join connections" obj=join id=ce119162e042 l=127.0.0.1:8000 r=[2401:4900:8838:8063:f0b0:1866:e957:b3ba]:54384
lollm-1   | OLLAMA API IS http://host.docker.internal:11434/api
lollm-1   | INFO:     2401:4900:8838:8063:f0b0:1866:e957:b3ba:0 - "GET / HTTP/1.1" 200 OK

NVIDIA GPU を搭載していないシステムでテストする場合は、Compose ファイルの deploy 属性をスキップできます。 

ngrok エンドポイントの出力を監視します。 私たちの場合、それは示しています: https://94e1-223-185-128-160.ngrok-free.app/

次に、次の ngrok webhook URL に ngrok webhook URL に /msg を追加します: https://94e1-223-185-128-160.ngrok-free.app/

次に、SendblueのwebhooksURLセクションに追加して保存します(図 3)。 ngrok サービスは、ポート 8000 で lollmm サービスを公開し、ngrok.io ドメインを使用してパブリック インターネットへのセキュリティで保護されたトンネルを提供するように構成されています。 

ngrok サービス ログは、Web サービスを開始し、トンネルとのクライアント セッションを確立したことを示します。 また、トンネル セッションが開始され、lollmm サービスで正常に確立されたことも示しています。

ngrok サービスは、ngrok サービスにアクセスするために必要な、指定された ngrok 認証トークンを使用するように構成されています。 全体として、ngrok サービスは正しく実行されており、lollmm サービスへの安全なトンネルを確立できます。

webhook への ngrok 認証トークンの追加を示す sendblue のスクリーンショット。
図 3: ngrok 認証トークンを webhook に追加します。

ngrok コンテナを実行するときにエラーログがないことを確認します (図 4)。

local-llm-messenger-ngrok-1 ログ出力を示すスクリーンショット。
図 4: ログにエラーがないか確認しています。

LoLLM Messenger コンテナがアクティブに稼働していることを確認します (図 5)。

local-llm-messenger-ngrok-1 ステータスを示す画面。
図 5: LoLLM Messenger コンテナが実行されていることを確認します。

ログは、Ollama サービスが指定されたポート (11434) を開き、着信接続をリッスンしていることを示しています。 ログには、Ollama サービスがホスト マシンの /home/ollama ディレクトリをコンテナ内の /home/ollama ディレクトリにマウントしたことも示されています。

全体として、Ollama サービスは正しく実行されており、推論のための AI モデルを提供する準備ができています。

機能のテスト

lollmサービスの機能をテストするには、まず連絡先番号をSendblueダッシュボードに追加する必要があります。 その後、Sendblue番号にメッセージを送信し、lollmmサービスからの応答を観察できるはずです(図 6)。

sendblue番号に送信されたメッセージとlollmサービスからの応答を示すimessage画像。
図 6: lollmサービスのテスト機能。

Sendblueプラットフォームは、lollmmサービスの /msg エンドポイントにHTTPリクエストを送信し、lollmmサービスはこれらのリクエストを処理して適切なレスポンスを返します。

  1. lollmm サービスは、ポート 8000でリッスンするように設定されています。
  2. ngrok トンネルが開始され、 https://94e1-223-185-128-160.ngrok-free.app などの公開 URL が提供されます。
  3. lollmm サービスは、ルート パス (/) やその他のパス ( /favicon.ico など) への GET 要求を含む HTTP 要求を ngrok トンネルから受信します。 /predict/mdg、および /msg
  4. lollmm サービスは、これらのリクエストに対して、成功したリクエストの場合は 200 OK、存在しないパスへのリクエストの場合は 404 Not Found など、適切な HTTP ステータスコードで応答します。
  5. ngrok トンネルは、クライアントが ngrok トンネルを介して lollmm サービスに接続していることを示す結合接続をログに記録します。
チャットでのリクエスト(/listおよび/help)と応答を示すImessage画像。
図 7:リクエストの送信とレスポンスの受信

/list を入力して LLM と初めてチャットするときは (図 7)、次のようにログを確認できます。

ngrok-1   | t=2024-07-09T02:34:30+0000 lvl=info msg="join connections" obj=join id=12bd50a8030b l=127.0.0.1:8000 r=18.223.220.3:44370
lollm-1   | OLLAMA API IS http://host.docker.internal:11434/api
lollm-1   | INFO:     18.223.220.3:0 - "POST /msg HTTP/1.1" 200 OK
ngrok-1   | t=2024-07-09T02:34:53+0000 lvl=info msg="join connections" obj=join id=259fda936691 l=127.0.0.1:8000 r=18.223.220.3:36712
lollm-1   | INFO:     18.223.220.3:0 - "POST /msg HTTP/1.1" 200 OK

次に、「/install codellama:latest」と入力してcodellamaモデルをインストールしましょう(図8)。

/install codellama:latestと入力して、codellamaモデルのimessageイメージのインストール。
図 8:「codellama」モデルのインストール。

次に示すように、デフォルトモデルを codellama:latest に設定すると、次のコンテナログが表示されます。

ngrok-1   | t=2024-07-09T03:39:23+0000 lvl=info msg="join connections" obj=join id=026d8fad5c87 l=127.0.0.1:8000 r=18.223.220.3:36282
lollm-1   | setting default model 
lollm-1   | INFO:     18.223.220.3:0 - "POST /msg HTTP/1.1" 200 OK

lollmmサービスは正しく実行されており、ngrokトンネルからのHTTPリクエストを処理できます。 ngrok トンネル URL を使用して、HTTP リクエストを適切なパスに送信することで lollmm サービスの機能をテストできます (図 9)。

「FIFA ワールド カップで優勝したのは誰ですか 2022など、機能をテストするために送信されたサンプルの質問を示す Imessage 画像".
図 9: メッセージング機能のテスト

結論

LoLLM Messengerは、メッセージングアプリ内のLLM統合の限界を押し広げたいと考えている開発者や愛好家にとって貴重なツールです。 これにより、開発者は特定のニーズに合わせてカスタムチャットボットを作成したり、メッセージにリアルタイムの感情分析を追加したり、メッセージングエクスペリエンスでまったく新しいAI機能を探索したりできます。 

まず、 GitHub の LoLLM Messenger プロジェクト を探索し、ローカル LLM の可能性を発見できます。

さらに詳しく