Wordcraft で AI ライティング アシスタントを作成する

私たちはストーリーが大好きです。ストーリーを語るなど、創造的な文章を書くのはやりがいがあり、やりがいのある仕事です。しかし 空白のページから独自のストーリーを作成するのは 大変に思えることもあれば 圧倒されることもあります人工知能(AI)の生成モデルは、空白のページから進んでナラティブを構築するのに役立つ優れたツールです。

このチュートリアルでは、Google の People and AI Research チームが開発した AI を活用した文章作成ツールである Wordcraft を拡張する方法について説明します。このウェブ アプリケーションでは、Gemini API を使用して、アイデアの生成、記事の一部の作成、コンテンツの修正により詳細を追加することにより、少しずつストーリーを構築できます。独自の文章スタイルに近づけるために Wordcraft を変更し、ワークフローをサポートする新しい文章コントロールを作成できます。

プロジェクトの概要と、プロジェクトを構築する担当者からの分析情報を含むプロジェクトを拡張する方法については、AI ライティング アシスタント - Google AI で構築するをご覧ください。まだ作成していない場合は、次の手順でプロジェクトの拡張を開始できます。

プロジェクトの設定

ここでは、Wordcraft プロジェクトを開発とテスト用に設定する手順を説明します。前提条件のソフトウェアをインストールし、コード リポジトリからプロジェクトのクローンを作成して、構成のインストールを実行して、いくつかの環境変数を設定する必要があります。これらの手順を完了したら、プロジェクトを実行して設定をテストできます。

前提条件をインストールする

Wordcraft プロジェクトは、Node と npm を使用してパッケージを管理し、アプリケーションを実行します。次のインストール手順は、Linux ホストマシン用です。

必要なソフトウェアをインストールするには:

  • お使いのプラットフォームのインストール手順に沿って、nodenpm をインストールします。

プロジェクトのクローンを作成して構成する

プロジェクト コードをダウンロードし、npm インストール コマンドを使用して必要な依存関係をダウンロードし、プロジェクトを構成します。プロジェクトのソースコードを取得するには、git ソース管理ソフトウェアが必要です。
プロジェクト コードをダウンロードして構成するには:

  1. 次のコマンドを使用して、git リポジトリのクローンを作成します。
    git clone https://github.com/PAIR-code/wordcraft
    
  2. Wordcraft プロジェクトのルート ディレクトリに移動します。
    cd wordcraft/
    
  3. インストール コマンドを実行して依存関係をダウンロードし、プロジェクトを構成します。
    npm install
    

環境変数を設定する

Wordcraft コード プロジェクトの実行に必要な環境変数(具体的には Google Gemini API キー)を設定します。次のインストール手順は、Linux ホストマシン用です。

環境変数を設定するには:

  1. Google Gemini API キーを取得して、キー文字列をコピーします。
  2. Wordcraft プロジェクトのルート ディレクトリに移動します。
    cd wordcraft/
    
  3. API キーを環境変数として設定します。Linux ホストでは、次のコマンドを使用します。
    touch .env
    echo "API_KEY="<YOUR_API_KEY>"" > .env
    

設定をテストする

これで、デバイスで Wordcraft を実行して、プロジェクトの設定をテストできるようになりました。この手順は省略可能ですが、行うことをおすすめします。

Wordcraft の開始画面

インストールと設定をテストするには:

  1. Wordcraft プロジェクトのルート ディレクトリに移動します。
    cd wordcraft/
    
  2. このプロジェクトによって開発モードでプロジェクトを実行します。
    npm run dev
    
  3. ウェブブラウザで Wordcraft ユーザー インターフェースに移動します。特定のアドレスは、前のコマンドの出力に表示されます。次に例を示します。
    http://localhost:3000/
    

プロンプトの例のテキストを変更する

Wordcraft コマンドのユーザー インターフェース Wordcraft は、新しいストーリーを開始するコマンドやテキストを生成コマンドなど、文章作成支援オペレーションごとに一連のサンプルを使用して、AI 生成モデル用のプロンプトを作成します。サンプルは、生成モデルがストーリーのテキストを生成する際のガイドとなります。オペレーションの例を変更することで、別のパターンや文章スタイルに合わせて出力を変更できます。このアプローチは、Wordcraft で思いどおりに記述を作成する簡単な方法です。

次の例は、Wordcraft の new_story サンプルの変更を示しています。この変更の目標は、AI 生成モデルに「内部の独白」アプローチを使用してストーリーの導入部を作成し、ミステリー小説に適したスタイルを使用するように指示することです。このようなストーリーの導入例をいくつか記述することで、生成モデルを一般的なパターンに合わせつつ、別のテーマの導入モデルを生成できます。

Wordcraft で新しい事例のサンプルを変更するには:

  1. wordcraft/app/context/json/new_story.json ファイルを開きます。
  2. JSON ファイルの全体的な構造を維持しながら、例を変更します。以下は、内部のモノローグ スタイルを使用したミステリー ストーリーの紹介の変更例です。
    [
      {
        "topic": "scientist disappears and their research into a new technology is gone",
        "target": "I got the call from the chief early Tuesday morning, before I'd even had a second sip of coffee. Terrible timing. Something about a researcher disappearing from the local university. Unusual for the research lab to ask for assistance, so I headed over to main lab building."
      },
      {
        "topic": "a young woman wakes up with no memory",
        "target": "An unfamiliar ceiling with harsh, white lights greeted my eyes as I opened them. I looked around. White walls, medical equipment, a hospital? Wait. Where am I? How did I get here?!"
      },
      {
        "topic": "old man tries to recall an important task as his memories gradually fade away",
        "target": "What was I supposed to do today? Feels like it was important. I stared into the kitchen cabinet full of mismatched mugs, mirroring my own confusion. What was it? Like someone is...in danger? A chill shot down my spine, but the details skittered off and hid in some dark corner of my head."
      },
      {
        "topic": "billionaire is found dead in a hotel room",
        "target": "People meet their end every day, some naturally, some unnaturally. After 17 years of working as a homicide detective in Seattle, I'd seen a lot more of the unnatural variety than most. Comes with the job, along with a hard-learned sense of what side of the line any given incident sat on. This...was murder."
      },
      {
        "topic": "retired covert operative gets dragged back into an old mission",
        "target": "Steam rose gently off the cup of Earl Grey sitting in front of me as I sat at the cafe, pedestrians and light traffic rolling by. The city was slowly waking up around me and my perfect Paris morning routine was shaping up nicely. Then I noticed that old familiar and unwelcome tingling on the back of my neck. I was being watched."
      }
    ]
  3. 変更を「new_story.json」ファイルに保存します。

変更した新しいストーリーのオペレーションをテストするには:

  1. Wordcraft プロジェクトのルート ディレクトリに移動します。
    cd wordcraft/
    
  2. プロジェクトを開発モードで実行します。すでに実行中の場合は、アプリを停止して再起動する必要があります。
    npm run dev
    
  3. ウェブブラウザで Wordcraft ユーザー インターフェースに移動します。特定のアドレスは、前のコマンドの出力に表示されます。次に例を示します。
    http://localhost:3000/
    
  4. Wordcraft のメインメニューに移動し、[Start a New Story] を選択します。
  5. 新しいストーリーのプロンプトを更新するか、目的に変更して、[新しいストーリーを開始] を選択します。

この手法を使用して、Wordcraft の既存の記事作成コントロールをすべて変更できます。wordcraft/app/context/json/ ディレクトリのサンプルを更新して、他のストーリー コントロールを変更してみます。

新しい書き込みコントロールの作成

Wordcraft でキャラクター ユーザー インターフェースを導入 Wordcraft アプリは、アプリの右側にある [コントロール] タブにある [テキストを生成] ボタンや [文を書き換える] ボタンと同様に、新しい記述コントロールを追加できるように設計されています。こうした変更には多少の労力がかかりますが、ワークフローと目標に合わせて Wordcraft の機能を組み立てることができます。

次の変更例では、Wordcraft 用の新しい文字コントロールを作成します。これを使用して、ストーリーに新しいキャラクターを紹介し、そのキャラクターの属性を説明することができます。このコントロールの基礎は、前述の「新しいストーリーを開始」コントロールなどの他の Wordcraft コントロールと同じです。文字の導入方法の例をいくつか記述した JSON ファイルを作成します。残りの変更では ユーザーインターフェースと AI プロンプト管理機能を追加します

例の作成

生成モデルに文字を導入する方法の例をいくつか記述します。たとえば、ナレーターのように説明するか、主人公の経験に基づいて紹介するか、次の例では、後者のアプローチを使用して、メイン キャラクターの観点から新しいキャラクターを導入しています。新しい JSON ファイルを使用して、次の例を追加します。

新しいコントロールの例を追加するには:

  1. wordcraft/app/context/json/new_character.json ファイルを作成します。
  2. JSON ファイルにサンプルを作成します。この例では、それぞれの例に、プロンプト テキストを表す character 説明フィールドと、想定される出力を示す target フィールドがあります。
    [
      {
        "character": "A character who is helpful and modest.",
        "target": "\"You lost, buddy?\" came a voice from behind me. Turning, I discovered a man dressed in a simple but presentable outfit. Small signs of age and loose threads hinted that these clothes, and the man himself, had seen better days."
      },
      {
        "character": "A character who is attractive and devious.",
        "target": "Stepping out of the alley a little too quickly, I collided with something solidly muscular and surprisingly delicately scented. \"Sorry.\" I managed, regaining my balance. \"Easy there, buddy, you're gonna hurt yourself,\" came the reply from a man with an almost feline grace, further reinforced by a stare that reminded me of a hunting cat assessing its potential prey."
      },
      {
        "character": "A character who is old and hesitant.",
        "target": "\"Excuse me. Do you know the way to the train station from here?\" I looked up from my phone to see a elderly woman in a threadbare coat, purse clutched with two hands in front of her. \"I-I'm supposed to meet my nephew there. Do... do you think you can help me?\""
      },
      {
        "character": "A character who is intelligent and aloof.",
        "target": "Bookish. That was my immediate reaction to this person I now saw in front of me. \"You're finally here. Did you read the notes I sent you?\" The voice sat squarely in between feminine and masculine intonation. \"No, of course you didn't.\" Dismissing my answer before I'd even formulated one. Annoyance immediately flushed through me."
      },
      {
        "character": "A character who is clumsy and energetic.",
        "target": "\"Whoa!\" was the only warning I had before someone slammed into my back, almost knocking me off my feet. \"I'm so sorry! WOOO! These skates are a RUSH!\" The apology came from a rather loud redhead wearing rollerblades, dark glasses and a very beefy-looking pair of headphones. That explained the volume of the apology."
      }
    ]
  3. 変更を new_character.json ファイルに保存します。

サンプルを作成したら、この新しい文字コントロールのプロンプト コンテンツを反映するように app/context/schema.ts ファイルと index.ts ファイルを変更します。

サンプルを schema.ts ファイルに追加するには:

  • wordcraft/app/context/schema.ts ファイルを変更して、新しい文字のサンプルデータ構造を含めます。
    export const newStorySchema = z.object({
      topic: z.string(),
      target: z.string(),
    });
    
    // add the following:
    export const newCharacterSchema = z.object({
      character: z.string(),
      target: z.string(),
    });

これらの新しい例に関連するオペレーション タイプを定義します。この新しいタイプにより、プロンプトの例をユーザー インターフェースとプロンプトのビルドコードに接続できます。これらは、後のステップで変更します。

新しいオペレーション タイプを作成するには

  • wordcraft/app/core/shared/types.ts ファイルを変更して、新しい文字オペレーション タイプを追加します。
    export const enum OperationType {
      ...
      NEW_CHARACTER = 'NEW_CHARACTER', // add to list of types
      ...
    }

index.ts ファイルでサンプルを登録するには:

  1. wordcraft/app/context/index.ts ファイルで、新しいスキーマをインポートします。
    import {
      continueSchema,
      ...
      newCharacterSchema // add new schema
    } from './schema';
    
  2. 新しい JSON ファイルを newCharacterJson としてインポートします。
    import newCharacterJson from './json/new_character.json';
    
  3. 新しいキャラクターのサンプル コンテンツをアプリのコンテキストに登録します。
    export class WordcraftContext {
      constructor() {
      ...
        this.registerExamples(
          OperationType.NEW_CHARACTER,
          newCharacterSchema,
          newCharacterJson
        );
      ...
    }
  4. NewCharacterExample タイプをエクスポートします。
    export type NewCharacterExample = z.infer<typeof newCharacterSchema>;
    

ユーザー インターフェースを構築する

コンテンツ生成の例を作成して登録したら、新しいコントロールのユーザー インターフェースを作成できます。このフェーズの作業の大部分は、新しいオペレーション クラスを作成し、そのクラスを Wordcraft アプリケーションのメインコードに登録することです。

新しいオペレーションを作成するには:

  1. wordcraft/app/core/operations/ ディレクトリで、既存のオペレーション クラスをテンプレートとして使用して、新しいオペレーション クラスを作成します。新しい文字コントロールでは、new_story_operation.ts クラスのコピーを作成し、名前を new_character_operation.ts に変更できます。
  2. クラスに新しい名前を付け、OperationSite 値を 1 つ以上定義して、ユーザー インターフェースにコントロールを表示するタイミングを指定します。
    export class NewCharacterOperation extends ChoiceOperation {
      static override isAvailable(operationSite: OperationSite) {
        return (
          operationSite === OperationSite.END_OF_SECTION ||
          operationSite === OperationSite.EMPTY_SECTION
        );
      }
    
  3. このオペレーションに id を設定します。
      static override id = OperationType.NEW_CHARACTER;
    
  4. スキーマ パラメータの値を反映するように、get 関数と run 関数を更新します。このコードでは、AI プロンプトで使用するプロンプト テキストをユーザー インターフェースから取得します。
      private get character(): string {
        return NewCharacterOperation.controls.character.value;
      }
    
      async run() {
        const params = { character: this.character };
        const choices = await this.getModel().newCharacter(params);
    
        this.setChoices(choices);
      }
    
  5. ユーザー インターフェースのテキストと説明を更新します。
      static override getButtonLabel() {
        return 'introduce character';
      }
    
      static override getDescription() {
        return 'Introduce a new character at the cursor.';
      }
    
      static override controls = {
        character: new TextareaControl({
          prefix: 'prompt',
          description: 'A prompt to introduce a new character.',
          value: 'A new character.',
        }),
      };
    

Wordcraft アプリケーションに新しいオペレーションを登録するには:

  1. wordcraft/app/core/operations/index.ts ファイルで、新しいオペレーションのインポートを追加します。
    import {NewCharacterOperation} from './new_character_operation';
    
  2. 同じ index.ts ファイルで、NewCharacterOperation クラスのエクスポートを追加します。
    export {
      ...
      NewCharacterOperation, // add this class
      ...
    };
  3. wordcraft/app/main.ts ファイルで、新しいオペレーションを登録します。
    const operationsService = wordcraftCore.getService(OperationsService);
    operationsService.registerOperations(
      ...
      Operations.NewCharacterOperation, // add new operation
      ...
    );
    

プロンプト処理を作成する

新しいコントロールの作成の最後のフェーズとして、AI 生成モデルのプロンプトの生成とレスポンスを処理するコードを作成します。作業の主な部分は、wordcraft/app/models/gemini/prompts/ ディレクトリにプロンプト ハンドラを作成することです。このハンドラは、ユーザー インターフェースから入力を受け取り、生成モデルに渡すプロンプトを作成します。

プロンプト パラメータのインターフェースを定義するには:

  • wordcraft/app/core/shared/interfaces.ts ファイルで、パラメータを指定する新しいオペレーションのインターフェースを追加します。
    export interface NewCharacterPromptParams {
      character: string;
    }
    

新しいオペレーションのプロンプト ハンドラを定義するには:

  1. wordcraft/app/models/gemini/prompts/ ディレクトリで、既存のオペレーション クラスの 1 つをテンプレートとして使用して、新しいプロンプト ハンドラクラスを作成します。新しい文字コントロールでは、new_story.ts クラスのコピーを作成し、出発点として名前を new_character.ts に変更します。
  2. プロンプト ハンドラ関数を定義し、NewCharacterExample クラスをインポートします。
    import { NewCharacterPromptParams } from '@core/shared/interfaces';
    import { NewCharacterExample, WordcraftContext } from '../../../context';
    import { OperationType } from '@core/shared/types';
    import { GeminiModel } from '..';
    
    export function makePromptHandler(model: GeminiModel, context: WordcraftContext) {
      ...
    }
    
  3. AI モデル プロンプトのユーザー インターフェース入力を取得する generatePrompt() 関数を作成します。
      function generatePrompt(character: string) {
        const prefix = "Here's a character description: ";
        const suffix = "Introduce this character in the story.";
    
        if (character.trim() === '') {
          return 'Introduce a new character to the story.';
        } else {
          return `${prefix}${model.wrap(character)}\n${suffix}`;
        }
      }
  4. getPromptContext() 関数を作成して、ユーザー インターフェースの入力とサンプル レスポンスを組み合わせ、完全なプロンプトを作成します。
      function getPromptContext() {
        const examples = context.getExampleData(
          OperationType.NEW_CHARACTER
        );
        let promptContext = model.getPromptPreamble();
        examples.forEach((example) => {
          const { character, target } = example;
          const prompt = generatePrompt(character);
          promptContext += `${prompt} ${model.wrap(target)}\n\n`;
        });
        return promptContext;
      }

新しい文字プロンプト ハンドラを統合するには:

  1. wordcraft/app/models/gemini/index.ts ファイルで、新しいキャラクター オペレーションのプロンプト ハンドラをインポートします。
    import {makePromptHandler as newCharacter} from './prompts/new_character';
  2. newCharacter プロンプト ハンドラのオーバーライド定義を追加します。
      override newCharacter = this.makePromptHandler(newCharacter);

プロンプト パラメータをモデル定義に登録するには:

  1. wordcraft/app/models/model.ts ファイルで、新しい NewCharacterPromptParams インターフェースのインポートを追加します。
    import {
      ...
      NewCharacterPromptParams,
      ...
    } from '@core/shared/interfaces';
  2. newCharacter プロンプト パラメータをモデルクラスに追加します。
      async newCharacter(params: NewCharacterPromptParams): Promise<ModelResults> {
        throw new Error('Not yet implemented');
      }

新しい書き込みコントロールをテストする

作成したコントロールを Wordcraft インターフェースでテストする準備が整います。続行する前に、コンパイル エラーがないかコードを確認してください。

新しいキャラクター コントロールをテストするには:

  1. Wordcraft プロジェクトのルート ディレクトリに移動します。
    cd wordcraft/
    
  2. プロジェクトを開発モードで実行します。
    npm run dev
    
  3. ウェブブラウザで Wordcraft ユーザー インターフェースに移動します。特定のアドレスは、前のコマンドの出力に表示されます。次に例を示します。
    http://localhost:3000/
    
  4. Wordcraft アプリケーションで、新しいストーリーを作成するか、既存のストーリーを開きます。
  5. ストーリーの編集領域で、カーソルをストーリーの末尾に移動します。右側の [コントロール] タブに、キャラクターの導入コントロールが表示されます。
  6. [キャラクター紹介] フィールドに新しいキャラクターの簡単な説明を入力し、[キャラクター紹介] ボタンを選択します。

参考情報

Wordcraft プロジェクトの詳細については、コード リポジトリをご覧ください。このチュートリアルで説明する変更は、この pull リクエストで確認できます。

本番環境のアプリケーション

大規模なユーザー向けに Wordcraft のカスタマイズ版をデプロイする予定の場合は、Google Gemini API の使用がレート制限やその他の使用制限の対象となる可能性があるので注意してください。ドキュメント エージェントなどの Gemini API を使用して本番環境アプリケーションを構築することを検討している場合は、アプリのスケーラビリティと信頼性を高める Google Cloud Vertex AI サービスを確認してください。