見出し画像

【必見】Claude 3.5 SonnetのArtifacts内でローカルLLM(Gemini nano)を無料実行!コードも完全公開

ClaudeのArtifacts内でGemini Nanoを使ってリアルタイム翻訳アプリを実行方法を解説します。コード付きです。

必要なもの

  • パソコン

  • Claudeの会員登録(無料版でOK)

  • Chrome Canaryのインストール(最新の機能が使える)

革命児、登場 - Claude 3.5 SonnetとArtifacts機能の衝撃

安い・早い・強いの三拍子

皆さん、AIの世界で今、とんでもないことが起きているんです。その名も「Claude 3.5 Sonnet」。このAIモデル、ただ者じゃありません。特に注目なのが「Artifacts」という機能なんですが、これがまた曲者。

想像してみてください。あなたがアイデアを口にすると、目の前でコードが踊り出す。ウェブサイトのデザインが形になる。そう、まるで魔法のように。しかも、その場で修正もできちゃうんです。「ちょっと、この色変えてよ」なんて言えば、ホイっと変わっちゃう。

例えば、今までエンジニアリングの知見がなかったPMなどが、これを使えば頭の中にあるアイデアを形にできるわけです。

もちろんこの翻訳アプリも100%Claudeで書いていて、私は一切修正していません。

小さな巨人、Gemini nano登場!Googleの秘密兵器

一番小さいナノモデル

一方、Googleも黙ってはいません。「Gemini nano」という小さな巨人を送り込んできました。

この子、すごいんです。スマホやタブレットで直接動くんですよ。しかも、ネットがなくてもOK。プライバシーを気にする人にはうってつけ。テキストを生成したり、画像を認識したり、音声を理解したり...まるでポケットの中に万能選手を忍ばせているような感じです。

例えば、海外旅行中に見つけた謎の料理。「これ何?」って聞くだけで、その場で教えてくれちゃう。オフラインでも使えるから、山奥でも大丈夫。冒険好きの人には、最高の相棒になりそうですね。

Artifacts×Gemini nano

さあ、ここからが本当の驚きです。なんと、Claude 3.5 SonnetのArtifacts機能を使って、Gemini nanoを動かすことができるんです!これって、まさに最強のAIコンビネーションじゃないですか?

でも、どうやってそんなことができるの?って思いますよね。実は、Artifacts機能の中でブラウザのAPIを使って、Gemini nanoを呼び出すことができるんです。これ、めちゃくちゃ画期的なんですよ!

想像してみてください。今までは安くはない金額を払って、OpenAIやClaudeのAPIを呼び出してAIアプリを開発していたわけです。

これを無料で好きなだけ呼び出せるなら最高じゃないですか?
しかもオフラインでも大丈夫なので、飛行機の中でももちろん大丈夫です。

Artifacts×Gemini nanoでリアルタイム翻訳

基本的には以下の3ステップで実行できます

1. Google Canaryをnpakaさんの記事を参考にインストール

私はM2 Macで行いました。

Chrome の Gemini Nano を試す

2. ClaudeのArtifacts機能を有効にする

トップページから変更ができる

まず、Claude 3.5 Sonnetにアクセスして、Artifacts機能を有効にしましょう。次に、私が用意したコードをClaude 3.5 Sonnetに入力します。このコードは、ArtifactsとGemini nanoを連携させる魔法の呪文みたいなものです。

3. 「このコードをartifacts内で実行して」と頼む

import React, { useState, useEffect, useRef } from 'react';
import { Loader2, ArrowRight } from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Alert, AlertDescription } from "@/components/ui/alert";

const TranslationComponent = () => {
  // ステート変数の定義
  const [inputText, setInputText] = useState(''); // 入力テキスト
  const [translatedText, setTranslatedText] = useState(''); // 翻訳されたテキスト
  const [error, setError] = useState(''); // エラーメッセージ
  const [isLoading, setIsLoading] = useState(false); // ローディング状態
  const sessionRef = useRef(null); // AIセッションの参照
  const abortControllerRef = useRef(null); // リクエストのキャンセル用コントローラー

  // コンポーネントのマウント時にAIセッションを初期化
  useEffect(() => {
    const initializeSession = async () => {
      try {
        // ジェネリックセッションが作成可能かチェック
        const canCreate = await window.ai.canCreateGenericSession();
        if (canCreate !== "no") {
          // セッションを作成
          sessionRef.current = await window.ai.createTextSession();
        } else {
          setError("セッションを作成できません");
        }
      } catch (err) {
        setError("セッション初期化エラー: " + err.message);
      }
    };
    initializeSession();

    // クリーンアップ関数:コンポーネントのアンマウント時にセッションを破棄
    return () => {
      if (sessionRef.current) {
        sessionRef.current.destroy();
      }
    };
  }, []);

  // 入力テキストが変更されるたびに翻訳を実行
  useEffect(() => {
    const translateText = async () => {
      // 入力テキストが空の場合は翻訳をクリア
      if (!sessionRef.current || inputText.trim() === '') {
        setTranslatedText('');
        setIsLoading(false);
        return;
      }

      // 既存のリクエストがある場合はキャンセル
      if (abortControllerRef.current) {
        abortControllerRef.current.abort(); 
      }

      try {
        // 新しいAbortControllerを作成
        abortControllerRef.current = new AbortController();
        setError(''); 
        setTranslatedText('');
        setIsLoading(true);

        // 翻訳リクエストを送信
        const stream = sessionRef.current.promptStreaming(
          `Translate the following Japanese text to English: "${inputText}"`, 
          { signal: abortControllerRef.current.signal }
        );

        // ストリームから翻訳結果を受信
        for await (const chunk of stream) {
          // 翻訳テキストの前後の引用符を削除し、余分な空白を削除
          setTranslatedText(chunk.trim().replace(/^["']|["']$/g, ''));
        }
      } catch (err) {
        // AbortError以外のエラーの場合にエラーメッセージを設定
        if (err.name !== 'AbortError') { 
          setError("翻訳エラー: " + err.message);
        } 
      } finally {
        setIsLoading(false);
      }
    };

    translateText();

    // クリーンアップ関数:コンポーネントの再レンダリング時に実行中のリクエストをキャンセル
    return () => {
      if (abortControllerRef.current) { 
        abortControllerRef.current.abort();
      }
    };
  }, [inputText]);

  // 入力テキストの変更ハンドラ
  const handleInputChange = (e) => {
    setInputText(e.target.value);
  };

  // UIのレンダリング
  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-100 to-purple-100 flex items-center justify-center p-4">
      <Card className="w-full max-w-md">
        <CardHeader>
          <CardTitle className="text-2xl font-bold text-center text-gray-800">リアルタイム翻訳</CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          {/* 日本語入力フィールド */}
          <div className="space-y-2">
            <label htmlFor="japaneseInput" className="text-sm font-medium text-gray-700">
              日本語テキスト
            </label>
            <Input
              id="japaneseInput"
              value={inputText}
              onChange={handleInputChange}
              placeholder="ここに入力してください..."
              className="w-full"
            />
          </div>
          {/* 矢印の区切り線 */}
          <div className="relative">
            <div className="absolute inset-0 flex items-center">
              <div className="w-full border-t border-gray-300" />
            </div>
            <div className="relative flex justify-center text-sm">
              <span className="px-2 bg-white text-gray-500">
                <ArrowRight className="w-6 h-6 text-blue-500" />
              </span>
            </div>
          </div>
          {/* 英語翻訳結果表示エリア */}
          <div className="space-y-2">
            <label className="text-sm font-medium text-gray-700">英語翻訳</label>
            <div className="w-full p-3 bg-gray-50 border border-gray-200 rounded-md min-h-[60px] text-gray-800 relative">
              {isLoading ? (
                <div className="absolute inset-0 flex items-center justify-center">
                  <Loader2 className="w-6 h-6 text-blue-500 animate-spin" />
                </div>
              ) : (
                translatedText
              )}
            </div>
          </div>
          {/* エラーメッセージ表示 */}
          {error && (
            <Alert variant="destructive">
              <AlertDescription>{error}</AlertDescription>
            </Alert>
          )}
        </CardContent>
      </Card>
    </div>
  );
};

export default TranslationComponent;

ほんとにこれだけです

入力した文章が、リアルタイムで英語に翻訳されるんです!
しかも、これ全部オフラインで行われているんですよ。すごくないですか?
試しにWifiをオフにしてみてください。

このガイドを読んで、「えっ、そんな簡単にできるの?」って思った人もいるかもしれません。でも、本当にそれくらい簡単なんです。AIの最先端技術を、まるでおもちゃで遊ぶように体験できる。そんな時代が、もう目の前に来ているんです。

無料で始められる、あなただけのAIプロダクト

最後に強調したいのが、これらの技術が基本的に無料で使えるということ。

今まで高額な費用がかかっていたAIアプリ開発が、誰でも気軽に始められるようになりました。

あなたの頭の中にあるアイデアを、すぐに形にできる。
そして、それを世界中の人々と共有できる。

これって、まさにAI革命の始まりじゃないでしょうか?


この記事が気に入ったらサポートをしてみませんか?