Claude ArtifactsをローカルLLMやGeminiでも使いたい

はじめに

少し前にClaudeに実装されたArtifactsはLLM・プログラマー界隈には大きな影響を与えました。

また、同時に発表されたClaude 3.5 Sonnetと同時に使うことで、Webアプリを誰でも作れる時代を感じさせてくれました。

しかし、Claude 3.5 Sonnetは無料で使うと、1日数回のやり取りしかできません。なんとかして、(無料で)もっと使ってみたいという欲望が生まれてきました。

とはいえ、Artifactsの実装は一見するとそこまで難しいようには見えないので、そのうちGoogleやOpenAIも同様の対話型ビジュアルチャットを実装する気がします。

でも、それまで待てない私はGoogle検索の海を彷徨い、見つけてしまいました。

prompt2ui

見つけたのはこの動画です。prompt2uiというLLMのWeb UI(Artifacts like)とOllamaを組み合わせて、ローカルLLMでアプリを開発してみる動画です。

動画を見た所、prompt2uiが動けばollamaに限らず、様々なLLM APIが使えそうです。

今回はこれをDocker環境で試してみる話となります。

環境構築

Web UIなのでリモートのDocker上に環境構築しました。いつものようにDev Containerを使っています。

以下、プロジェクトのディレクトリ構成です。

ollama_prompt2ui_test
├── .devcontainer
│   ├── Dockerfile
│   ├── devcontainer.json
│   └── docker-compose.yml
├── .ollama
└── prompt2ui (git clone)

.ollamaディレクトリだけ作っておいてください。その後は、.devcontainer以下のファイルを作成して、コンテナをビルドしてください

Dockerfile

ベースはdebian:bullseye-slimにしました。node:20とかをベースにすると、vscodeのユーザーとUIDが衝突して、vs code上でファイルの権限が無くなってしまったので、バニラのdebian上にnode jsの実行環境を作りました。

node.jsはversion 22を入れると、後で怒られるのでversion 20を入れました。

FROM debian:bullseye-slim

ENV DEBIAN_FRONTEND=noninteractive

ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN apt-get update \
    && groupadd --gid $USER_GID $USERNAME \
    && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
    && apt-get install -y sudo \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME \
    && apt-get -y install locales \
    && localedef -f UTF-8 -i ja_JP ja_JP.UTF-8

RUN apt-get -y install git
RUN apt-get -y install curl

RUN curl -SL https://deb.nodesource.com/setup_20.x | bash
RUN apt-get install -y nodejs

devcontainer.json

名前とサービス名を設定してください。私は、面倒なので同じものを設定しています。拡張機能好きなものを入れてください。今回はほぼプログラムをいじらないので、拡張機能はなくてもいいです。

{
    "name": "ollama_prompt2ui_test",
    "service": "ollama_prompt2ui_test",
    "dockerComposeFile": "docker-compose.yml",
    "remoteUser": "vscode",
    "workspaceFolder": "/work",
    "customizations": {
      "vscode": {
        "extensions": []
      }
    }
}

docker-compose.yml

サービス名を先ほど設定したものと同一にしてください。

また、ollamaを別サービスとして入れて、API経由で利用できるようにしておきます。

version: '3'
services:
  ollama_prompt2ui_test:
    container_name: 'ollama_prompt2ui_test-container'
    hostname: 'ollama_prompt2ui_test-container'
    build: .
    restart: always
    working_dir: '/work' 
    tty: true
    volumes:
      - type: bind
        source: ..
        target: /work
  
  ollama:
    volumes:
      - type: bind
        source: ../.ollama
        target: /root/.ollama
    container_name: ollama
    tty: true
    image: ollama/ollama:latest
    ports:
      - 11434:11434
    environment:
      - OLLAMA_KEEP_ALIVE=24h
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

prompt2uiのクローン

コンテナに入れたら、prompt2uiをクローンします。

git clone https://github.com/sullyo/prompt2ui.git

クローン後は、ディレクトリ移動して依存ライブラリ・モジュールをインストールします。

cd prompt2ui
npm install

数分待つと依存ライブラリ・モジュールのインストールが終わります。

OllamaでArtifacts

モデルのダウンロード

Ollamaを使ってArtifactsライクなWeb UIを試してみます。

まずは、Ollamaが正しく起動しているかを確かめます。

{Dockerを立てたサーバーのIP}:11434でブラウザでアクセスすると、Ollama is runningとでます。これでOKです。リモート上に立ててない人は、localhost:11434でOKです。

そしたら、モデルをダウンロードします。ターミナルを開いて、{ip-address:11434}/api/pullでモデルをダウンロードできます。

curl 192.168.0.200:11434/api/pull -d '{"name":"deepseek-coder-v2:16b"}'

今回は、プログラムに特化したローカルLLMであるdeepspeek-coder-v2を試してみます。

数十分待つとダウンロードが終わります。

prompt2uiのapi呼び出しの編集

次に、prompt2uiのapi呼び出し部分を編集します。

編集するファイルはprompt2ui/src/app/api/chat/route.tsです。

import { systemPrompt } from "@/app/api/chat/prompt";
import {createOpenAI} from "@ai-sdk/openai";
import { CoreMessage, streamText } from "ai";

export async function POST(req: Request) {
  const { messages }: { messages: CoreMessage[] } = await req.json();
  const openai = createOpenAI({
    baseURL:"http://192.168.0.200:11434/v1/",
    apiKey:"ollama",
  });

  const result = await streamText({
    model: openai("deepseek-coder-v2:16b"),
    system: systemPrompt,
    messages,
  });
  return result.toAIStreamResponse();
}

もともとは、anthropic(Claude)のAPIを呼び出すようになっていましたが、これをOpen AIの呼び出しへと書き換えます。OllamaのAPIサーバーはOpen AI準拠なので、これで動作します。

起動

書き換えたら、prompt2uiを起動します。

npm run dev

正しく起動できれば以下のようなログが流れます。

vscode@ollama_prompt2ui_test-container:/work/prompt2ui$ npm run dev

> sonnet-coder@0.1.0 dev
> next dev

  ▲ Next.js 14.2.4
  - Local:        http://localhost:3000
  - Environments: .env

 ✓ Starting...
/bin/sh: 1: pnpm: not found
 ✓ Ready in 2.8s

http://localhost:3000へアクセスしてみます。

数秒待たないと、Web UIが表示されませんが、少し待つと表示されます。

左側にチャット、右側に実行画面とコードが見れるようになっています。

「簡単なTodoアプリをReactを使って作成して」とチャットすると、コードが表示されましたが、Web UIは固まってしまいました。

何度か試しましたが、Youtubeの動画のようにスムーズにいきませんでした。実行マシンのスペック不足でしょうか?

GeminiでArtifacts

prompt2uiのapi呼び出しの編集

次は、Geminiでも試したいと思います。要はAPIを正しく呼び出せれば、動くと思うので。

まず、GeminiのAPI KEYを取得してきます。これはGoogle AI Studioから取得できます。

そしたら、prompt2uiの.env.exampleを.envへと名前変更し、中身を書き換えます。ここにGeminiのAPI Keyを書き込んでおきます。

GOOGLE_API_KEY="xxxxx"

そしたら、ai-sdk/googleを追加パッケージに追記します。パッケージの管理はpackage.jsonっぽいのでここに@ai-sdk/googleを追記しました。

{
  "name": "sonnet-coder",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@ai-sdk/anthropic": "^0.0.23",
    "@ai-sdk/openai": "^0.0.33",
    "@ai-sdk/google": "^0.0.24",
...

その後、route.tsを編集します。パスはprompt2ui/src/app/api/chat/route.tsです。

import { systemPrompt } from "@/app/api/chat/prompt";
import { Google } from "@ai-sdk/google";
import { CoreMessage, streamText } from "ai";

export async function POST(req: Request) {
  const { messages }: { messages: CoreMessage[] } = await req.json();
  const google = new Google({ apiKey: process.env.GOOGLE_API_KEY || '' })
  const result = await streamText({
    model: google.generativeAI("models/gemini-1.5-flash"),
    system: systemPrompt,
    messages,
  });
  return result.toAIStreamResponse();
}

パッケージを追記したのでnpm installをしておきます

npm install

あとはollamaのときと同様です。

起動

npm run devでprompt2uiを起動します。

npm run dev

正しく起動できれば以下のようなログが流れます。

vscode@ollama_prompt2ui_test-container:/work/prompt2ui$ npm run dev

> sonnet-coder@0.1.0 dev
> next dev

  ▲ Next.js 14.2.4
  - Local:        http://localhost:3000
  - Environments: .env

 ✓ Starting...
/bin/sh: 1: pnpm: not found
 ✓ Ready in 2.8s

http://localhost:3000へアクセスしてみます。少し待つと、Web UIが表示されました。

先ほどと同様に「簡単なTodoアプリをReactを使って作成して」とチャットすると、今度はフリーズすることなく、プログラムを吐き出しました。

しかし、youtubeの動画では自動でプログラムをコンパイルして、右側の実行画面が更新されていた様に感じましたが、自動ではコンパイルされていません。

codeタブを開いて、出力されたプログラムを貼り付けると、previewが更新されました。

追加のボタンが白くて見えませんが、タスクの記入欄の横にあります。

英語でも聞いてみましたが、自動で実行画面を表示してくれませんでした。

うまくプログラム部分を認識できていないような気がします。横にコピペするだけですが、この一手間が面倒に感じます。

まとめ

今回はprompt2uiというArtifactsライクなWeb UIを使ってみました。

左側にチャット、右側にコードとプレビューという配置になっており、Claude Artifactsを再現したようなチャット画面が使えました。

そして、ollamaやgeminiで利用できたので、Claudeの無料制限を気にせず使えるかもしれません。

ollamaではdeepseek-coder-v2を使いましたが、マシンのスペック不足が原因で、快適には利用できませんでした。

geminiの無料APIを利用すると、快適にチャットができることも確認しました。

しかし、自動でプログラムを読み取って、プレビューしてくれる機能がうまく動作しませんでした。これは今後の課題とします(解決するまでにGeminiがArtifactライクなチャット画面を実装する気もする)。

タイトルとURLをコピーしました