12
7
生成AIに関する記事を書こう!
Qiita Engineer Festa20242024年7月17日まで開催中!

Claude 3.5 Sonnet の Artifacts 機能とは?使い方を分かりやすく解説!

Posted at

はじめに

Claude 3.5 Sonnet が先月公開されました。

Claude 3.5 Sonnetは、Anthropic社が開発した最新の大規模言語モデルです。前バージョンと比較して、大幅な性能向上が見られます。

image.png

注目なのはArtifactsという機能です。LLMが生成したコードを右側の実行環境でプレビューしつつ、対話形式で修正を依頼することができます。従来のチャットベースのやり取りに加え、より視覚的で直感的な開発体験を提供します。
今回はこのArtifacts機能を使った例をご紹介します。

アプリのフロントを作成し、プレビューしながら修正する

Reactで作成されたコードをpreviewしつつ修正できます。

次のようなアプリを生成してください
1. 英語の入力ボックスに英文を入力する
2. 入力した英文は、クリック可能なUIとなる

image.png

上記のように指示を出すと、Claude 3.5 Sonnetはリアルタイムにコードを生成し、右側のプレビューエリアに反映してくれます。
一発では狙い通り完成しませんが、プレビューを見ながら具体的な指示をチャットで伝えることで、コードを修正していくことができます。

何度か対話を続けることで、以下のようなところまで作成できました。

image.png

このコードをローカルの環境にコピーし、裏側で翻訳APIを繋げます。
今回はGoogle Cloud のCloud Translation APIを使用しました。
バックエンド部分は非同期処理で同期的に待ってしまったりと、ところどころ実装が不十分でしたが、
フロントの知識が皆無でも、Claude 3.5 Sonnetの力を借りることで、以下のような英語学習アプリが作成できました。

英語翻訳アプリ.gif

具体的なコードは以下のようになりました。

import React, { useState, useCallback } from 'react';
import axios from 'axios';

// Mock translation dictionaries
let wordTranslations = {
    'Hello': 'こんにちは',
    'world': '世界',
    'This': 'これは',
    'is': 'です',
    'a': '1つの',
    'test': 'テスト',
    'sentence': '',
    'for': 'のための',
    'translation': '翻訳',
    'I': '私は',
    'love': '愛します',
    'programming': 'プログラミング',
    'in': '',
    'JavaScript': 'ジャバスクリプト',
};

let fullTextTranslations = {
    'Hello world': 'こんにちは、世界',
    'This is a test sentence for translation': 'これは翻訳のためのテスト文です',
    'I love programming in JavaScript': '私はJavaScriptでのプログラミングが大好きです',
};

// Google Cloud Translation APIを使用した翻訳関数
const translateTextWithAPI = async (text) => {
    const apiKey = '';  // ここに取得したAPIキーを入力してください
    const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;

    try {
        const response = await axios.post(url, {
            q: text,
            target: 'ja'
        });
        console.log("text: %s, translated: %s", text, response.data.data.translations[0].translatedText);
        return response.data.data.translations[0].translatedText;
    } catch (error) {
        console.error('Error translating text:', error);
        return '翻訳に失敗しました';
    }
};

const translateTextWithAPIbyword = async (word) => {
    const translatedText = await translateTextWithAPI(word);
    wordTranslations[word.toLowerCase()] = translatedText;
}
// Simulated API call for word translation
const translateWord = async (word) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log("keyとなるword: %s", word);
            const translation = wordTranslations[word.toLowerCase()] || `[${word}の訳]`;
            wordTranslations[word.toLowerCase()] = translation;
            resolve(translation);
        }, 100);
    });
};

// Simulated API call for full text translation
const translateFullText = async (text) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            const translation = fullTextTranslations[text] || text.split(' ').map(word => wordTranslations[word.toLowerCase()] || `[${word}の訳]`).join(' ');
            fullTextTranslations[text.toLowerCase()] = translation;
            resolve(translation);
        }, 500);
    });
};

const Word = ({ word }) => {
    const [showTranslation, setShowTranslation] = useState(false);

    const handleClick = () => {
        setShowTranslation(!showTranslation);
    };

    return (
        <span className="inline-block mr-1 mb-2">
            <span
                onClick={handleClick}
                className="cursor-pointer hover:bg-blue-100 p-1 rounded"
            >
                {word}
            </span>
            {showTranslation && (
                <span className="block text-sm text-gray-600">
                    {wordTranslations[word.toLowerCase()] || `[${word}の訳]`}
                </span>
            )}
        </span>
    );
};

const InteractiveTranslatorApp = () => {
    const [inputText, setInputText] = useState('');
    const [displayText, setDisplayText] = useState('');
    const [fullTranslation, setFullTranslation] = useState('');
    const [isLoading, setIsLoading] = useState(false);

    const handleInputChange = useCallback((e) => {
        setInputText(e.target.value);
    }, []);

    const handleSubmit = useCallback(async (e) => {
        e.preventDefault();
        setIsLoading(true);
        console.log('送信ボタンがクリックされました');
        console.log('入力テキスト:', inputText);

        const words = inputText.split(' ');

        let results = [];
        for (let word of words) {
            results.push(translateTextWithAPIbyword(word));
        }
        await Promise.all(results);

        results = [];
        for (let word of words) {
            results.push(translateWord(word));
        }
        await Promise.all(results);

        setDisplayText(inputText);
        setIsLoading(false);
    }, [inputText]);

    const handleButtonClick = useCallback(() => {
        console.log('ボタンが直接クリックされました');
    }, []);

    const handleFullTranslation = useCallback(async () => {
        setIsLoading(true);
        const translatedText = await translateTextWithAPI(displayText);
        // const translatedText = await translateFullText(displayText);
        setFullTranslation(translatedText);
        setIsLoading(false);
    }, [displayText]);

    return (
        <div className="p-4 max-w-2xl mx-auto">
            <h1 className="text-2xl font-bold mb-4">インタラクティブ英語翻訳アプリ</h1>
            <form onSubmit={handleSubmit} className="mb-4">
                <textarea
                    value={inputText}
                    onChange={handleInputChange}
                    placeholder="英語の文章を入力してください"
                    className="w-full p-2 border border-gray-300 rounded"
                    rows="4"
                />
                <button
                    type="submit"
                    onClick={handleButtonClick}
                    className="mt-2 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
                    disabled={isLoading}
                >
                    {isLoading ? '処理中...' : '送信'}
                </button>
            </form>
            {displayText && (
                <div className="mt-4">
                    <div className="p-4 bg-gray-100 rounded">
                        {displayText.split(' ').map((word, index) => (
                            <Word key={`${word}-${index}`} word={word} />
                        ))}
                    </div>
                    <button
                        onClick={handleFullTranslation}
                        className="mt-2 px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
                        disabled={isLoading}
                    >
                        {isLoading ? '処理中...' : '全体翻訳'}
                    </button>
                    {fullTranslation && (
                        <div className="mt-2 p-4 bg-yellow-100 rounded">
                            <h2 className="font-bold mb-2">全体翻訳:</h2>
                            <p>{fullTranslation}</p>
                        </div>
                    )}
                </div>
            )}
            <div className="mt-4">
                <p>デバッグ情報:</p>
                <p>入力テキスト: {inputText}</p>
                <p>表示テキスト: {displayText}</p>
                <p>全体翻訳: {fullTranslation}</p>
            </div>
        </div>
    );
};

export default InteractiveTranslatorApp;

svg形式で図を作成し、プレビューを閲覧しながら調整

diffusionモデルを使った画像生成はできませんが、svg形式で画像を作成しプレビューすることができます。

svgで、会社のロゴを作成してください

image.png

Claude 3.5 Sonnetは、抽象的な指示に対しても、具体的なアウトプットを生成することができます。もちろん、ロゴのデザインも調整可能です。

次に、JKKのロゴを作ってもらいます。

Create the logo of Juncture Keeps Key Technologies, Inc (JKK Technologies) in svg

image.png

会社名を与えることで、それを反映したロゴを作成してくれます。

もう少し会社情報を入れてみましょう。

JKK Technologies is a company that specializes in data analysis, so please create a logo that will make that feature easily recognizable!

image.png

会社の特徴を伝えることで、ロゴにそれを象徴する要素を加えることも可能です。

なかなかかわいいロゴが作成できました。

終わりに

Claude 3.5 Sonnetは、Artifacts機能によって、従来のLLMよりもさらにインタラクティブで直感的な開発体験を提供します。今回の例を通じて、その可能性を感じていただけたのではないでしょうか。今後、Claude 3.5 Sonnetがどのように活用されていくのか、非常に楽しみです。

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7