使用 Wordcraft 建構 AI 書寫助理

故事我們喜歡故事,述說故事和採用其他形式的創意寫作 不僅困難重重,也更值得回報然而,從空白網頁建構自己的故事 似乎相當困難,有時甚至令人頭昏腦脹人工智慧 (AI) 生成式模型是非常實用的工具,可協助您擺脫空白的頁面,建立論述內容。

本教學課程說明如何擴充 Wordcraft,這是由 Google 人力與 AI 研究團隊打造的 AI 技術輔助故事撰寫工具。這個網頁應用程式使用 Gemini API 協助您建構故事,而且要有初步的生成概念、撰寫報導部分,以及修改內容以新增更多詳細資料。您可以修改 Wordcraft,讓自己的寫作更符合自己的風格,並建構新的寫作控制項,讓工作流程更完善。

如需專案簡介影片並瞭解如何延伸,包括建構程式開發人員的深入分析,請查看 AI Writer Assistant - Build with Google AI。否則,您可以按照下列操作說明開始擴充專案。

專案設定

以下操作說明會逐步引導您設定 Wordcraft 專案進行開發和測試。您需要安裝前置軟體、從程式碼存放區複製專案、執行設定安裝作業,以及設定幾個環境變數。完成上述步驟後,您可以執行專案來測試設定。

安裝必備條件

Wordcraft 專案使用 Node 和 npm 管理套件並執行應用程式。下列安裝操作說明適用於 Linux 主機,

如何安裝必要的軟體:

複製並設定專案

下載專案程式碼,並使用 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 來測試專案設定。這是選用步驟,但建議執行。

文字工具啟動畫面

如何測試安裝和設定:

  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. 更新新的故事提示或將其變更為所需內容,然後選取「start new story」(建立新的故事)

您可以使用這個技巧,修改 Wordcraft 中的所有現有的故事撰寫控制項。嘗試透過更新 wordcraft/app/context/json/ 目錄中的範例來變更其他故事控制項。

建立新的書寫控制項

Wordcraft 介紹角色使用者介面 Wordcraft 應用程式經過精心設計,您可以擴充應用程式的新撰寫控制項,就像應用程式右側「控制項」分頁中的產生文字重新撰寫句子按鈕一樣。要進行這些修改雖然有些繁瑣,但您可以依據自己的工作流程和目標調整 Word 生成的功能。

以下範例修改內容會為 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.tsindex.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 值,指定控制項顯示在使用者介面的時間點。
    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. 更新 getrun 函式,以反映結構定義參數的值。這段程式碼負責從使用者介面取得提示文字,用於 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/ 目錄中,使用其中一個現有的作業類別做為範本,建立新的提示處理常式類別。對於新的字元控制項,您可以複製 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. 建構 generatePrompt() 函式,取得 AI 模型提示的使用者介面輸入內容。
      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. 在故事編輯區域中,將遊標移到故事的結尾處。在右側的「 Controls」分頁中,應會顯示「引入字元」控制項。
  6. 在「Intro character」欄位中,輸入新字元的簡短說明,然後選取「Intro character」按鈕。

其他資源

如要進一步瞭解 Wordcraft 專案,請參閱程式碼存放區。您可在此提取要求中,查看本教學課程中所述的變更。

正式版應用程式

如果您打算為大量目標對象部署自訂的 Wordcraft 版本,請注意使用 Google Gemini API 時可能必須遵守頻率限制和其他使用限制。如果您考慮使用 Gemini API (例如文件代理程式) 建構正式版應用程式,請查看 Google Cloud Vertex AI 服務,以提高應用程式的擴充性和可靠性。